@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.js
CHANGED
|
@@ -58,6 +58,7 @@ __export(index_exports, {
|
|
|
58
58
|
assertPostgrestSuccess: () => assertPostgrestSuccess,
|
|
59
59
|
bindFetch: () => bindFetch,
|
|
60
60
|
buildInferenceRequestBody: () => buildInferenceRequestBody,
|
|
61
|
+
buildResponseFormat: () => buildResponseFormat,
|
|
61
62
|
collectAssistantTextFromUiSegments: () => collectAssistantTextFromUiSegments,
|
|
62
63
|
collectionRecordToRowWithMeta: () => collectionRecordToRowWithMeta,
|
|
63
64
|
collectionRecordsToRowWithMeta: () => collectionRecordsToRowWithMeta,
|
|
@@ -85,8 +86,11 @@ __export(index_exports, {
|
|
|
85
86
|
runAgentChatStream: () => runAgentChatStream,
|
|
86
87
|
runAgentChatStreamForUi: () => runAgentChatStreamForUi,
|
|
87
88
|
runAgentChatStreamLenient: () => runAgentChatStreamLenient,
|
|
89
|
+
streamObjectFromContext: () => streamObjectFromContext,
|
|
88
90
|
toRagableResult: () => toRagableResult,
|
|
89
|
-
|
|
91
|
+
tryParsePartialJson: () => tryParsePartialJson,
|
|
92
|
+
unwrapPostgrest: () => unwrapPostgrest,
|
|
93
|
+
wrapStreamTextAsObject: () => wrapStreamTextAsObject
|
|
90
94
|
});
|
|
91
95
|
module.exports = __toCommonJS(index_exports);
|
|
92
96
|
|
|
@@ -2357,6 +2361,72 @@ function decodeJwtExpiry(jwt) {
|
|
|
2357
2361
|
}
|
|
2358
2362
|
}
|
|
2359
2363
|
|
|
2364
|
+
// src/partial-json.ts
|
|
2365
|
+
function tryParsePartialJson(text) {
|
|
2366
|
+
const trimmed = text.trim();
|
|
2367
|
+
if (!trimmed) return void 0;
|
|
2368
|
+
try {
|
|
2369
|
+
return JSON.parse(trimmed);
|
|
2370
|
+
} catch {
|
|
2371
|
+
}
|
|
2372
|
+
const repaired = repairOpenStructures(trimmed);
|
|
2373
|
+
if (!repaired) return void 0;
|
|
2374
|
+
try {
|
|
2375
|
+
return JSON.parse(repaired);
|
|
2376
|
+
} catch {
|
|
2377
|
+
const noTrailingComma = stripTrailingCommas(trimmed);
|
|
2378
|
+
const repaired2 = repairOpenStructures(noTrailingComma);
|
|
2379
|
+
if (!repaired2) return void 0;
|
|
2380
|
+
try {
|
|
2381
|
+
return JSON.parse(repaired2);
|
|
2382
|
+
} catch {
|
|
2383
|
+
return void 0;
|
|
2384
|
+
}
|
|
2385
|
+
}
|
|
2386
|
+
}
|
|
2387
|
+
function repairOpenStructures(text) {
|
|
2388
|
+
const first = text[0];
|
|
2389
|
+
if (first !== "{" && first !== "[") {
|
|
2390
|
+
return text;
|
|
2391
|
+
}
|
|
2392
|
+
const stack = [];
|
|
2393
|
+
let inString = false;
|
|
2394
|
+
let escaped = false;
|
|
2395
|
+
for (let i = 0; i < text.length; i++) {
|
|
2396
|
+
const ch = text[i];
|
|
2397
|
+
if (escaped) {
|
|
2398
|
+
escaped = false;
|
|
2399
|
+
continue;
|
|
2400
|
+
}
|
|
2401
|
+
if (ch === "\\") {
|
|
2402
|
+
escaped = true;
|
|
2403
|
+
continue;
|
|
2404
|
+
}
|
|
2405
|
+
if (ch === '"') {
|
|
2406
|
+
inString = !inString;
|
|
2407
|
+
continue;
|
|
2408
|
+
}
|
|
2409
|
+
if (inString) continue;
|
|
2410
|
+
if (ch === "{") stack.push("}");
|
|
2411
|
+
else if (ch === "[") stack.push("]");
|
|
2412
|
+
else if (ch === "}" || ch === "]") {
|
|
2413
|
+
if (stack.length === 0) return null;
|
|
2414
|
+
stack.pop();
|
|
2415
|
+
}
|
|
2416
|
+
}
|
|
2417
|
+
let safe = text;
|
|
2418
|
+
if (inString) {
|
|
2419
|
+
safe += '"';
|
|
2420
|
+
}
|
|
2421
|
+
safe = safe.replace(/,\s*$/, "").replace(/:\s*$/, ": null");
|
|
2422
|
+
let suffix = "";
|
|
2423
|
+
for (let i = stack.length - 1; i >= 0; i--) suffix += stack[i];
|
|
2424
|
+
return safe + suffix;
|
|
2425
|
+
}
|
|
2426
|
+
function stripTrailingCommas(text) {
|
|
2427
|
+
return text.replace(/,(\s*[}\]])/g, "$1").replace(/,\s*$/, "");
|
|
2428
|
+
}
|
|
2429
|
+
|
|
2360
2430
|
// src/stream-parts.ts
|
|
2361
2431
|
function normalizeFinishReason(raw) {
|
|
2362
2432
|
switch (raw) {
|
|
@@ -2566,7 +2636,7 @@ var ZERO_USAGE = {
|
|
|
2566
2636
|
completionTokens: 0,
|
|
2567
2637
|
totalTokens: 0
|
|
2568
2638
|
};
|
|
2569
|
-
function buildInferenceRequestBody(params) {
|
|
2639
|
+
function buildInferenceRequestBody(params, responseFormat) {
|
|
2570
2640
|
const body = {
|
|
2571
2641
|
model: params.model,
|
|
2572
2642
|
messages: params.messages
|
|
@@ -2577,8 +2647,18 @@ function buildInferenceRequestBody(params) {
|
|
|
2577
2647
|
if (typeof params.maxTokens === "number") body.max_tokens = params.maxTokens;
|
|
2578
2648
|
if (typeof params.topP === "number") body.top_p = params.topP;
|
|
2579
2649
|
if (params.reasoningEffort) body.reasoning_effort = params.reasoningEffort;
|
|
2650
|
+
if (responseFormat) body.response_format = responseFormat;
|
|
2580
2651
|
return body;
|
|
2581
2652
|
}
|
|
2653
|
+
function buildResponseFormat(params) {
|
|
2654
|
+
const json_schema = {
|
|
2655
|
+
name: params.name ?? "Output",
|
|
2656
|
+
schema: params.schema,
|
|
2657
|
+
strict: params.strict ?? true
|
|
2658
|
+
};
|
|
2659
|
+
if (params.description) json_schema.description = params.description;
|
|
2660
|
+
return { type: "json_schema", json_schema };
|
|
2661
|
+
}
|
|
2582
2662
|
async function consumeInferenceStream(body, broadcast, deferreds) {
|
|
2583
2663
|
const reader = body.getReader();
|
|
2584
2664
|
const decoder = new TextDecoder();
|
|
@@ -2829,6 +2909,190 @@ var RagableBrowserAiClient = class {
|
|
|
2829
2909
|
);
|
|
2830
2910
|
return { text, reasoning, usage, finishReason, toolCalls };
|
|
2831
2911
|
}
|
|
2912
|
+
/**
|
|
2913
|
+
* Stream a JSON-Schema-constrained response. Matches Vercel AI SDK's
|
|
2914
|
+
* `streamObject` shape — returns a synchronous result with `partialObjectStream`
|
|
2915
|
+
* (best-effort incremental parses) and `object` (the final parsed JSON).
|
|
2916
|
+
*
|
|
2917
|
+
* ```ts
|
|
2918
|
+
* const { partialObjectStream, object } = client.ai.streamObject({
|
|
2919
|
+
* model: "accounts/fireworks/models/kimi-k2p5",
|
|
2920
|
+
* schema: {
|
|
2921
|
+
* type: "object",
|
|
2922
|
+
* properties: {
|
|
2923
|
+
* title: { type: "string" },
|
|
2924
|
+
* tags: { type: "array", items: { type: "string" } },
|
|
2925
|
+
* },
|
|
2926
|
+
* required: ["title", "tags"],
|
|
2927
|
+
* },
|
|
2928
|
+
* messages: [{ role: "user", content: "Give me a blog post idea about AI." }],
|
|
2929
|
+
* });
|
|
2930
|
+
* for await (const partial of partialObjectStream) renderPreview(partial);
|
|
2931
|
+
* const final = await object;
|
|
2932
|
+
* ```
|
|
2933
|
+
*/
|
|
2934
|
+
streamObject(params) {
|
|
2935
|
+
return streamObjectFromContext(this.buildContext(), params);
|
|
2936
|
+
}
|
|
2937
|
+
/**
|
|
2938
|
+
* Non-streaming variant of {@link streamObject}. Resolves once the model
|
|
2939
|
+
* finishes; rejects if the final text isn't valid JSON for the schema.
|
|
2940
|
+
*/
|
|
2941
|
+
async generateObject(params) {
|
|
2942
|
+
const result = this.streamObject(params);
|
|
2943
|
+
for await (const _ of result.partialObjectStream) {
|
|
2944
|
+
void _;
|
|
2945
|
+
}
|
|
2946
|
+
const [object, usage, finishReason, toolCalls] = await Promise.all([
|
|
2947
|
+
result.object,
|
|
2948
|
+
result.usage,
|
|
2949
|
+
result.finishReason,
|
|
2950
|
+
result.toolCalls
|
|
2951
|
+
]);
|
|
2952
|
+
return { object, usage, finishReason, toolCalls };
|
|
2953
|
+
}
|
|
2954
|
+
};
|
|
2955
|
+
function streamObjectFromContext(ctx, params) {
|
|
2956
|
+
const textParams = {
|
|
2957
|
+
model: params.model,
|
|
2958
|
+
messages: params.messages,
|
|
2959
|
+
...params.system !== void 0 ? { system: params.system } : {},
|
|
2960
|
+
...typeof params.temperature === "number" ? { temperature: params.temperature } : {},
|
|
2961
|
+
...typeof params.maxTokens === "number" ? { maxTokens: params.maxTokens } : {},
|
|
2962
|
+
...typeof params.topP === "number" ? { topP: params.topP } : {},
|
|
2963
|
+
...params.signal !== void 0 ? { signal: params.signal } : {}
|
|
2964
|
+
};
|
|
2965
|
+
const responseFormat = buildResponseFormat({
|
|
2966
|
+
schema: params.schema,
|
|
2967
|
+
...params.schemaName !== void 0 ? { name: params.schemaName } : {},
|
|
2968
|
+
...params.schemaDescription !== void 0 ? { description: params.schemaDescription } : {}
|
|
2969
|
+
});
|
|
2970
|
+
const overrideCtx = {
|
|
2971
|
+
...ctx,
|
|
2972
|
+
// Wrap fetch to substitute the body. We can't change buildInferenceRequestBody
|
|
2973
|
+
// signature on the call site cleanly, so intercept here.
|
|
2974
|
+
fetch: ((input, init) => {
|
|
2975
|
+
if (init && typeof init.body === "string") {
|
|
2976
|
+
const parsed = JSON.parse(init.body);
|
|
2977
|
+
parsed.response_format = responseFormat;
|
|
2978
|
+
const newInit = { ...init, body: JSON.stringify(parsed) };
|
|
2979
|
+
return ctx.fetch(input, newInit);
|
|
2980
|
+
}
|
|
2981
|
+
return ctx.fetch(input, init);
|
|
2982
|
+
})
|
|
2983
|
+
};
|
|
2984
|
+
const inner = streamInferenceFromContext(overrideCtx, textParams);
|
|
2985
|
+
return wrapStreamTextAsObject(inner);
|
|
2986
|
+
}
|
|
2987
|
+
function wrapStreamTextAsObject(inner) {
|
|
2988
|
+
const partialBroadcast = new PartialObjectBroadcast();
|
|
2989
|
+
const objectDeferred = defer();
|
|
2990
|
+
void (async () => {
|
|
2991
|
+
let acc = "";
|
|
2992
|
+
let lastEmitted = /* @__PURE__ */ Symbol("none");
|
|
2993
|
+
try {
|
|
2994
|
+
for await (const delta of inner.textStream) {
|
|
2995
|
+
acc += delta;
|
|
2996
|
+
const candidate = tryParsePartialJson(acc);
|
|
2997
|
+
if (candidate !== void 0 && !sameSnapshot(candidate, lastEmitted)) {
|
|
2998
|
+
lastEmitted = candidate;
|
|
2999
|
+
partialBroadcast.push(candidate);
|
|
3000
|
+
}
|
|
3001
|
+
}
|
|
3002
|
+
const finalText = await inner.text;
|
|
3003
|
+
let finalObj;
|
|
3004
|
+
try {
|
|
3005
|
+
finalObj = JSON.parse(finalText);
|
|
3006
|
+
} catch (e) {
|
|
3007
|
+
const err = new RagableError(
|
|
3008
|
+
`Model output is not valid JSON: ${e.message}`,
|
|
3009
|
+
502,
|
|
3010
|
+
{
|
|
3011
|
+
code: "SDK_OBJECT_PARSE_FAILED",
|
|
3012
|
+
raw: finalText.slice(0, 1e3)
|
|
3013
|
+
}
|
|
3014
|
+
);
|
|
3015
|
+
partialBroadcast.fail(err);
|
|
3016
|
+
objectDeferred.reject(err);
|
|
3017
|
+
return;
|
|
3018
|
+
}
|
|
3019
|
+
if (!sameSnapshot(finalObj, lastEmitted)) {
|
|
3020
|
+
partialBroadcast.push(finalObj);
|
|
3021
|
+
}
|
|
3022
|
+
partialBroadcast.end();
|
|
3023
|
+
objectDeferred.resolve(finalObj);
|
|
3024
|
+
} catch (err) {
|
|
3025
|
+
partialBroadcast.fail(err);
|
|
3026
|
+
objectDeferred.reject(err);
|
|
3027
|
+
}
|
|
3028
|
+
})();
|
|
3029
|
+
return {
|
|
3030
|
+
textStream: inner.textStream,
|
|
3031
|
+
partialObjectStream: partialBroadcast.consume(),
|
|
3032
|
+
object: objectDeferred.promise,
|
|
3033
|
+
text: inner.text,
|
|
3034
|
+
usage: inner.usage,
|
|
3035
|
+
finishReason: inner.finishReason,
|
|
3036
|
+
toolCalls: inner.toolCalls
|
|
3037
|
+
};
|
|
3038
|
+
}
|
|
3039
|
+
function sameSnapshot(a, b) {
|
|
3040
|
+
if (a === b) return true;
|
|
3041
|
+
try {
|
|
3042
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
3043
|
+
} catch {
|
|
3044
|
+
return false;
|
|
3045
|
+
}
|
|
3046
|
+
}
|
|
3047
|
+
var PartialObjectBroadcast = class {
|
|
3048
|
+
constructor() {
|
|
3049
|
+
__publicField(this, "items", []);
|
|
3050
|
+
__publicField(this, "resolved", false);
|
|
3051
|
+
__publicField(this, "error", null);
|
|
3052
|
+
__publicField(this, "waiters", []);
|
|
3053
|
+
}
|
|
3054
|
+
push(item) {
|
|
3055
|
+
this.items.push(item);
|
|
3056
|
+
this.notify();
|
|
3057
|
+
}
|
|
3058
|
+
end() {
|
|
3059
|
+
if (this.resolved) return;
|
|
3060
|
+
this.resolved = true;
|
|
3061
|
+
this.notify();
|
|
3062
|
+
}
|
|
3063
|
+
fail(error) {
|
|
3064
|
+
if (this.resolved) return;
|
|
3065
|
+
this.error = error;
|
|
3066
|
+
this.resolved = true;
|
|
3067
|
+
this.notify();
|
|
3068
|
+
}
|
|
3069
|
+
notify() {
|
|
3070
|
+
const w = this.waiters;
|
|
3071
|
+
this.waiters = [];
|
|
3072
|
+
for (const fn of w) fn();
|
|
3073
|
+
}
|
|
3074
|
+
consume() {
|
|
3075
|
+
const self = this;
|
|
3076
|
+
return {
|
|
3077
|
+
[Symbol.asyncIterator]: () => {
|
|
3078
|
+
let idx = 0;
|
|
3079
|
+
return {
|
|
3080
|
+
next: async () => {
|
|
3081
|
+
while (true) {
|
|
3082
|
+
if (idx < self.items.length) {
|
|
3083
|
+
return { value: self.items[idx++], done: false };
|
|
3084
|
+
}
|
|
3085
|
+
if (self.resolved) {
|
|
3086
|
+
if (self.error) throw self.error;
|
|
3087
|
+
return { value: void 0, done: true };
|
|
3088
|
+
}
|
|
3089
|
+
await new Promise((res) => self.waiters.push(res));
|
|
3090
|
+
}
|
|
3091
|
+
}
|
|
3092
|
+
};
|
|
3093
|
+
}
|
|
3094
|
+
};
|
|
3095
|
+
}
|
|
2832
3096
|
};
|
|
2833
3097
|
|
|
2834
3098
|
// src/browser.ts
|
|
@@ -3691,6 +3955,63 @@ var RagableBrowserAgentsClient = class {
|
|
|
3691
3955
|
const source = this.runStreamParts(agentName, params);
|
|
3692
3956
|
return createStreamResultFromParts(source);
|
|
3693
3957
|
}
|
|
3958
|
+
/**
|
|
3959
|
+
* Same agent, same tools/instructions/RAG — but constrain the final output
|
|
3960
|
+
* to a JSON Schema. Matches `client.ai.streamObject` exactly so callers can
|
|
3961
|
+
* swap between raw inference and an agent without changing call shape.
|
|
3962
|
+
*
|
|
3963
|
+
* Tool calling and structured output are **compatible**: the model may call
|
|
3964
|
+
* the agent's tools as usual; the final assistant message is the schema-
|
|
3965
|
+
* conformant JSON. The agent's `agents/<name>.json` is unchanged — whether
|
|
3966
|
+
* the run is conversational or structured is decided by the call site.
|
|
3967
|
+
*
|
|
3968
|
+
* ```ts
|
|
3969
|
+
* const { partialObjectStream, object } = client.agents.runObject<Plan>(
|
|
3970
|
+
* "planner",
|
|
3971
|
+
* {
|
|
3972
|
+
* messages: [{ role: "user", content: "Plan a 3-day trip to Kyoto." }],
|
|
3973
|
+
* schema: {
|
|
3974
|
+
* type: "object",
|
|
3975
|
+
* properties: {
|
|
3976
|
+
* days: {
|
|
3977
|
+
* type: "array",
|
|
3978
|
+
* items: { type: "object", properties: { date: { type: "string" }, activities: { type: "array", items: { type: "string" } } } },
|
|
3979
|
+
* },
|
|
3980
|
+
* },
|
|
3981
|
+
* required: ["days"],
|
|
3982
|
+
* },
|
|
3983
|
+
* },
|
|
3984
|
+
* );
|
|
3985
|
+
* for await (const p of partialObjectStream) renderPreview(p);
|
|
3986
|
+
* console.log(await object);
|
|
3987
|
+
* ```
|
|
3988
|
+
*/
|
|
3989
|
+
runObject(agentName, params) {
|
|
3990
|
+
const responseFormat = buildResponseFormat({
|
|
3991
|
+
schema: params.schema,
|
|
3992
|
+
...params.schemaName !== void 0 ? { name: params.schemaName } : {},
|
|
3993
|
+
...params.schemaDescription !== void 0 ? { description: params.schemaDescription } : {}
|
|
3994
|
+
});
|
|
3995
|
+
const sourceParts = this.runStreamParts(agentName, {
|
|
3996
|
+
messages: params.messages,
|
|
3997
|
+
...params.signal !== void 0 ? { signal: params.signal } : {},
|
|
3998
|
+
responseFormat
|
|
3999
|
+
});
|
|
4000
|
+
const inner = createStreamResultFromParts(sourceParts);
|
|
4001
|
+
return wrapStreamTextAsObject(inner);
|
|
4002
|
+
}
|
|
4003
|
+
/** Non-streaming variant of {@link runObject}. */
|
|
4004
|
+
async generateObject(agentName, params) {
|
|
4005
|
+
const result = this.runObject(agentName, params);
|
|
4006
|
+
for await (const _ of result.partialObjectStream) void _;
|
|
4007
|
+
const [object, usage, finishReason, toolCalls] = await Promise.all([
|
|
4008
|
+
result.object,
|
|
4009
|
+
result.usage,
|
|
4010
|
+
result.finishReason,
|
|
4011
|
+
result.toolCalls
|
|
4012
|
+
]);
|
|
4013
|
+
return { object, usage, finishReason, toolCalls };
|
|
4014
|
+
}
|
|
3694
4015
|
async *runStreamParts(agentName, params) {
|
|
3695
4016
|
const { messages } = params;
|
|
3696
4017
|
if (!Array.isArray(messages) || messages.length === 0) {
|
|
@@ -3712,12 +4033,33 @@ var RagableBrowserAgentsClient = class {
|
|
|
3712
4033
|
role: m.role,
|
|
3713
4034
|
content: m.content
|
|
3714
4035
|
}));
|
|
3715
|
-
const
|
|
4036
|
+
const headers = new Headers(this.options.headers);
|
|
4037
|
+
headers.set("Content-Type", "application/json");
|
|
4038
|
+
const body = {
|
|
3716
4039
|
message: last.content,
|
|
3717
4040
|
...history.length > 0 ? { history } : {},
|
|
3718
|
-
...params.
|
|
3719
|
-
}
|
|
3720
|
-
|
|
4041
|
+
...params.responseFormat ? { response_format: params.responseFormat } : {}
|
|
4042
|
+
};
|
|
4043
|
+
const response = await this.fetchImpl(
|
|
4044
|
+
this.toUrl(
|
|
4045
|
+
this.websiteAgentPath(
|
|
4046
|
+
`/agents/${encodeURIComponent(agentName)}/chat/stream`
|
|
4047
|
+
)
|
|
4048
|
+
),
|
|
4049
|
+
{
|
|
4050
|
+
method: "POST",
|
|
4051
|
+
headers,
|
|
4052
|
+
body: JSON.stringify(body),
|
|
4053
|
+
...params.signal !== void 0 ? { signal: params.signal } : {}
|
|
4054
|
+
}
|
|
4055
|
+
);
|
|
4056
|
+
if (!response.ok) {
|
|
4057
|
+
const payload = await parseMaybeJsonBody(response);
|
|
4058
|
+
const message = extractErrorMessage(payload, response.statusText);
|
|
4059
|
+
throw new RagableError(message, response.status, payload);
|
|
4060
|
+
}
|
|
4061
|
+
if (!response.body) return;
|
|
4062
|
+
for await (const event of readSseStream(response.body)) {
|
|
3721
4063
|
const mapped = mapAgentEvent(event);
|
|
3722
4064
|
if (mapped) yield mapped;
|
|
3723
4065
|
}
|
|
@@ -3955,6 +4297,7 @@ function createClient(options) {
|
|
|
3955
4297
|
assertPostgrestSuccess,
|
|
3956
4298
|
bindFetch,
|
|
3957
4299
|
buildInferenceRequestBody,
|
|
4300
|
+
buildResponseFormat,
|
|
3958
4301
|
collectAssistantTextFromUiSegments,
|
|
3959
4302
|
collectionRecordToRowWithMeta,
|
|
3960
4303
|
collectionRecordsToRowWithMeta,
|
|
@@ -3982,7 +4325,10 @@ function createClient(options) {
|
|
|
3982
4325
|
runAgentChatStream,
|
|
3983
4326
|
runAgentChatStreamForUi,
|
|
3984
4327
|
runAgentChatStreamLenient,
|
|
4328
|
+
streamObjectFromContext,
|
|
3985
4329
|
toRagableResult,
|
|
3986
|
-
|
|
4330
|
+
tryParsePartialJson,
|
|
4331
|
+
unwrapPostgrest,
|
|
4332
|
+
wrapStreamTextAsObject
|
|
3987
4333
|
});
|
|
3988
4334
|
//# sourceMappingURL=index.js.map
|