@warmdrift/kgauto-compiler 2.0.0-alpha.33 → 2.0.0-alpha.35
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/chunk-P3TOAEG4.mjs +56 -0
- package/dist/glassbox/index.d.mts +3 -3
- package/dist/glassbox/index.d.ts +3 -3
- package/dist/glassbox-routes/format.d.mts +24 -0
- package/dist/glassbox-routes/format.d.ts +24 -0
- package/dist/glassbox-routes/format.js +86 -0
- package/dist/glassbox-routes/format.mjs +18 -0
- package/dist/glassbox-routes/index.d.mts +5 -149
- package/dist/glassbox-routes/index.d.ts +5 -149
- package/dist/glassbox-routes/react/index.d.mts +74 -0
- package/dist/glassbox-routes/react/index.d.ts +74 -0
- package/dist/glassbox-routes/react/index.js +819 -0
- package/dist/glassbox-routes/react/index.mjs +754 -0
- package/dist/index.d.mts +11 -2
- package/dist/index.d.ts +11 -2
- package/dist/index.js +325 -17
- package/dist/index.mjs +325 -17
- package/dist/{ir-DubC20e3.d.mts → ir-BAAHLfFL.d.mts} +37 -0
- package/dist/{ir-GnYPkpGo.d.ts → ir-B_ygNURd.d.ts} +37 -0
- package/dist/profiles.d.mts +1 -1
- package/dist/profiles.d.ts +1 -1
- package/dist/{types-2QzI0Ep1.d.mts → types-BoqPXoUb.d.mts} +1 -1
- package/dist/types-CJz1Ebvb.d.ts +149 -0
- package/dist/{types-DYcO82xh.d.ts → types-CXyKj6-K.d.ts} +1 -1
- package/dist/types-DDX6K2-p.d.mts +149 -0
- package/package.json +32 -6
package/dist/index.mjs
CHANGED
|
@@ -1725,8 +1725,295 @@ var CallError = class extends Error {
|
|
|
1725
1725
|
}
|
|
1726
1726
|
};
|
|
1727
1727
|
|
|
1728
|
-
// src/
|
|
1728
|
+
// src/streaming.ts
|
|
1729
1729
|
var ANTHROPIC_URL = "https://api.anthropic.com/v1/messages";
|
|
1730
|
+
async function streamAnthropic(request, apiKey, opts) {
|
|
1731
|
+
const { provider: _provider, ...body } = request;
|
|
1732
|
+
const fetchFn = opts.fetchImpl ?? fetch;
|
|
1733
|
+
let res;
|
|
1734
|
+
try {
|
|
1735
|
+
res = await fetchFn(ANTHROPIC_URL, {
|
|
1736
|
+
method: "POST",
|
|
1737
|
+
headers: {
|
|
1738
|
+
"x-api-key": apiKey,
|
|
1739
|
+
"anthropic-version": "2023-06-01",
|
|
1740
|
+
"content-type": "application/json"
|
|
1741
|
+
},
|
|
1742
|
+
body: JSON.stringify({ ...body, stream: true })
|
|
1743
|
+
});
|
|
1744
|
+
} catch (err) {
|
|
1745
|
+
return retryableError(0, "network_error", String(err), null);
|
|
1746
|
+
}
|
|
1747
|
+
if (!res.ok) {
|
|
1748
|
+
const errBody = await res.json().catch(() => ({}));
|
|
1749
|
+
return classifyHttpError(res.status, errBody);
|
|
1750
|
+
}
|
|
1751
|
+
let text = "";
|
|
1752
|
+
let inputTokens = 0;
|
|
1753
|
+
let outputTokens = 0;
|
|
1754
|
+
let cacheReadTokens;
|
|
1755
|
+
let cacheCreatedTokens;
|
|
1756
|
+
let stopReason;
|
|
1757
|
+
const toolBlocks = /* @__PURE__ */ new Map();
|
|
1758
|
+
try {
|
|
1759
|
+
await parseSSEStream(res, (event) => {
|
|
1760
|
+
if (!event.data) return;
|
|
1761
|
+
let payload;
|
|
1762
|
+
try {
|
|
1763
|
+
payload = JSON.parse(event.data);
|
|
1764
|
+
} catch {
|
|
1765
|
+
return;
|
|
1766
|
+
}
|
|
1767
|
+
const type = payload.type;
|
|
1768
|
+
if (type === "message_start") {
|
|
1769
|
+
const msg = payload.message;
|
|
1770
|
+
const usage = msg?.usage;
|
|
1771
|
+
if (usage) {
|
|
1772
|
+
inputTokens = usage.input_tokens ?? 0;
|
|
1773
|
+
outputTokens = usage.output_tokens ?? 0;
|
|
1774
|
+
if (typeof usage.cache_read_input_tokens === "number")
|
|
1775
|
+
cacheReadTokens = usage.cache_read_input_tokens;
|
|
1776
|
+
if (typeof usage.cache_creation_input_tokens === "number")
|
|
1777
|
+
cacheCreatedTokens = usage.cache_creation_input_tokens;
|
|
1778
|
+
}
|
|
1779
|
+
return;
|
|
1780
|
+
}
|
|
1781
|
+
if (type === "content_block_start") {
|
|
1782
|
+
const p = payload;
|
|
1783
|
+
const idx = p.index ?? 0;
|
|
1784
|
+
const block = p.content_block;
|
|
1785
|
+
if (block?.type === "tool_use" && block.id && block.name) {
|
|
1786
|
+
toolBlocks.set(idx, { id: block.id, name: block.name, argsJson: "" });
|
|
1787
|
+
}
|
|
1788
|
+
return;
|
|
1789
|
+
}
|
|
1790
|
+
if (type === "content_block_delta") {
|
|
1791
|
+
const p = payload;
|
|
1792
|
+
const delta = p.delta;
|
|
1793
|
+
if (!delta) return;
|
|
1794
|
+
if (delta.type === "text_delta" && typeof delta.text === "string") {
|
|
1795
|
+
text += delta.text;
|
|
1796
|
+
opts.onChunk(delta.text);
|
|
1797
|
+
} else if (delta.type === "input_json_delta" && typeof delta.partial_json === "string") {
|
|
1798
|
+
const idx = p.index ?? 0;
|
|
1799
|
+
const tool = toolBlocks.get(idx);
|
|
1800
|
+
if (tool) tool.argsJson += delta.partial_json;
|
|
1801
|
+
}
|
|
1802
|
+
return;
|
|
1803
|
+
}
|
|
1804
|
+
if (type === "message_delta") {
|
|
1805
|
+
const p = payload;
|
|
1806
|
+
if (p.delta?.stop_reason) stopReason = p.delta.stop_reason;
|
|
1807
|
+
if (typeof p.usage?.output_tokens === "number") outputTokens = p.usage.output_tokens;
|
|
1808
|
+
return;
|
|
1809
|
+
}
|
|
1810
|
+
});
|
|
1811
|
+
} catch (err) {
|
|
1812
|
+
return retryableError(0, "stream_interrupted", String(err), null);
|
|
1813
|
+
}
|
|
1814
|
+
const toolCalls = Array.from(toolBlocks.values()).map((b) => ({
|
|
1815
|
+
id: b.id,
|
|
1816
|
+
name: b.name,
|
|
1817
|
+
args: tryParseJson(b.argsJson) ?? {}
|
|
1818
|
+
}));
|
|
1819
|
+
const tokens = {
|
|
1820
|
+
input: inputTokens,
|
|
1821
|
+
output: outputTokens,
|
|
1822
|
+
total: inputTokens + outputTokens,
|
|
1823
|
+
cached: cacheReadTokens,
|
|
1824
|
+
cacheCreated: cacheCreatedTokens
|
|
1825
|
+
};
|
|
1826
|
+
const response = {
|
|
1827
|
+
text,
|
|
1828
|
+
structuredOutput: null,
|
|
1829
|
+
toolCalls,
|
|
1830
|
+
tokens,
|
|
1831
|
+
finishReason: stopReason,
|
|
1832
|
+
raw: { streamed: true, provider: "anthropic" }
|
|
1833
|
+
};
|
|
1834
|
+
return { ok: true, status: res.status, response };
|
|
1835
|
+
}
|
|
1836
|
+
async function streamOpenAILike(url, request, apiKey, providerLabel, opts) {
|
|
1837
|
+
const { provider: _provider, ...body } = request;
|
|
1838
|
+
const fetchFn = opts.fetchImpl ?? fetch;
|
|
1839
|
+
const reqBody = {
|
|
1840
|
+
...body,
|
|
1841
|
+
stream: true,
|
|
1842
|
+
stream_options: {
|
|
1843
|
+
...body.stream_options ?? {},
|
|
1844
|
+
include_usage: true
|
|
1845
|
+
}
|
|
1846
|
+
};
|
|
1847
|
+
let res;
|
|
1848
|
+
try {
|
|
1849
|
+
res = await fetchFn(url, {
|
|
1850
|
+
method: "POST",
|
|
1851
|
+
headers: {
|
|
1852
|
+
authorization: `Bearer ${apiKey}`,
|
|
1853
|
+
"content-type": "application/json"
|
|
1854
|
+
},
|
|
1855
|
+
body: JSON.stringify(reqBody)
|
|
1856
|
+
});
|
|
1857
|
+
} catch (err) {
|
|
1858
|
+
return retryableError(0, "network_error", String(err), null);
|
|
1859
|
+
}
|
|
1860
|
+
if (!res.ok) {
|
|
1861
|
+
const errBody = await res.json().catch(() => ({}));
|
|
1862
|
+
return classifyHttpError(res.status, errBody);
|
|
1863
|
+
}
|
|
1864
|
+
let text = "";
|
|
1865
|
+
let finishReason;
|
|
1866
|
+
let inputTokens = 0;
|
|
1867
|
+
let outputTokens = 0;
|
|
1868
|
+
let totalTokens;
|
|
1869
|
+
let cachedTokens;
|
|
1870
|
+
const toolBuffers = /* @__PURE__ */ new Map();
|
|
1871
|
+
try {
|
|
1872
|
+
await parseSSEStream(res, (event) => {
|
|
1873
|
+
if (!event.data) return;
|
|
1874
|
+
if (event.data === "[DONE]") return;
|
|
1875
|
+
let payload;
|
|
1876
|
+
try {
|
|
1877
|
+
payload = JSON.parse(event.data);
|
|
1878
|
+
} catch {
|
|
1879
|
+
return;
|
|
1880
|
+
}
|
|
1881
|
+
const choices = payload.choices;
|
|
1882
|
+
if (choices && choices.length > 0) {
|
|
1883
|
+
const choice = choices[0];
|
|
1884
|
+
const deltaContent = choice.delta?.content;
|
|
1885
|
+
if (typeof deltaContent === "string" && deltaContent.length > 0) {
|
|
1886
|
+
text += deltaContent;
|
|
1887
|
+
opts.onChunk(deltaContent);
|
|
1888
|
+
}
|
|
1889
|
+
const toolDeltas = choice.delta?.tool_calls;
|
|
1890
|
+
if (toolDeltas) {
|
|
1891
|
+
for (const tcDelta of toolDeltas) {
|
|
1892
|
+
const idx = tcDelta.index ?? 0;
|
|
1893
|
+
let buf = toolBuffers.get(idx);
|
|
1894
|
+
if (!buf) {
|
|
1895
|
+
buf = { id: tcDelta.id ?? `tc-${idx}`, name: "", argsJson: "" };
|
|
1896
|
+
toolBuffers.set(idx, buf);
|
|
1897
|
+
}
|
|
1898
|
+
if (tcDelta.id) buf.id = tcDelta.id;
|
|
1899
|
+
if (tcDelta.function?.name) buf.name += tcDelta.function.name;
|
|
1900
|
+
if (tcDelta.function?.arguments) buf.argsJson += tcDelta.function.arguments;
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
if (choice.finish_reason) finishReason = choice.finish_reason;
|
|
1904
|
+
}
|
|
1905
|
+
const usage = payload.usage;
|
|
1906
|
+
if (usage) {
|
|
1907
|
+
if (typeof usage.prompt_tokens === "number") inputTokens = usage.prompt_tokens;
|
|
1908
|
+
if (typeof usage.completion_tokens === "number") outputTokens = usage.completion_tokens;
|
|
1909
|
+
if (typeof usage.total_tokens === "number") totalTokens = usage.total_tokens;
|
|
1910
|
+
const details = usage.prompt_tokens_details;
|
|
1911
|
+
if (typeof details?.cached_tokens === "number") cachedTokens = details.cached_tokens;
|
|
1912
|
+
}
|
|
1913
|
+
});
|
|
1914
|
+
} catch (err) {
|
|
1915
|
+
return retryableError(0, "stream_interrupted", String(err), null);
|
|
1916
|
+
}
|
|
1917
|
+
const toolCalls = Array.from(toolBuffers.values()).filter((b) => b.name.length > 0).map((b) => ({
|
|
1918
|
+
id: b.id,
|
|
1919
|
+
name: b.name,
|
|
1920
|
+
args: tryParseJson(b.argsJson) ?? {}
|
|
1921
|
+
}));
|
|
1922
|
+
const tokens = {
|
|
1923
|
+
input: inputTokens,
|
|
1924
|
+
output: outputTokens,
|
|
1925
|
+
total: totalTokens ?? inputTokens + outputTokens,
|
|
1926
|
+
cached: cachedTokens
|
|
1927
|
+
};
|
|
1928
|
+
const response = {
|
|
1929
|
+
text,
|
|
1930
|
+
structuredOutput: null,
|
|
1931
|
+
toolCalls,
|
|
1932
|
+
tokens,
|
|
1933
|
+
finishReason,
|
|
1934
|
+
raw: { streamed: true, provider: providerLabel }
|
|
1935
|
+
};
|
|
1936
|
+
return { ok: true, status: res.status, response };
|
|
1937
|
+
}
|
|
1938
|
+
async function parseSSEStream(response, handler) {
|
|
1939
|
+
const body = response.body;
|
|
1940
|
+
if (!body) throw new Error("Response has no body for SSE parse");
|
|
1941
|
+
const reader = body.getReader();
|
|
1942
|
+
const decoder = new TextDecoder("utf-8");
|
|
1943
|
+
let buffer = "";
|
|
1944
|
+
for (; ; ) {
|
|
1945
|
+
const { value, done } = await reader.read();
|
|
1946
|
+
if (done) break;
|
|
1947
|
+
buffer += decoder.decode(value, { stream: true });
|
|
1948
|
+
let sep;
|
|
1949
|
+
while (sep = buffer.indexOf("\n\n"), sep !== -1) {
|
|
1950
|
+
const block = buffer.slice(0, sep);
|
|
1951
|
+
buffer = buffer.slice(sep + 2);
|
|
1952
|
+
const event = parseSSEBlock(block);
|
|
1953
|
+
if (event) handler(event);
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1956
|
+
if (buffer.length > 0) {
|
|
1957
|
+
const event = parseSSEBlock(buffer);
|
|
1958
|
+
if (event) handler(event);
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
function parseSSEBlock(block) {
|
|
1962
|
+
const lines = block.split(/\r?\n/);
|
|
1963
|
+
let eventName;
|
|
1964
|
+
const dataLines = [];
|
|
1965
|
+
for (const line of lines) {
|
|
1966
|
+
if (line.startsWith(":")) continue;
|
|
1967
|
+
if (line.startsWith("event:")) {
|
|
1968
|
+
eventName = line.slice(6).trim();
|
|
1969
|
+
} else if (line.startsWith("data:")) {
|
|
1970
|
+
dataLines.push(line.slice(5).trim());
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1973
|
+
if (dataLines.length === 0) return void 0;
|
|
1974
|
+
return { event: eventName, data: dataLines.join("\n") };
|
|
1975
|
+
}
|
|
1976
|
+
function tryParseJson(s) {
|
|
1977
|
+
if (typeof s !== "string" || s.length === 0) return void 0;
|
|
1978
|
+
try {
|
|
1979
|
+
const parsed = JSON.parse(s);
|
|
1980
|
+
return typeof parsed === "object" && parsed !== null ? parsed : void 0;
|
|
1981
|
+
} catch {
|
|
1982
|
+
return void 0;
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
function classifyHttpError(status, body) {
|
|
1986
|
+
const message = extractErrorMessage(body) ?? `HTTP ${status}`;
|
|
1987
|
+
if (status === 429)
|
|
1988
|
+
return { ok: false, status, errorType: "retryable", errorCode: "rate_limit", message, raw: body };
|
|
1989
|
+
if (status === 408)
|
|
1990
|
+
return { ok: false, status, errorType: "retryable", errorCode: "timeout", message, raw: body };
|
|
1991
|
+
if (status >= 500)
|
|
1992
|
+
return { ok: false, status, errorType: "retryable", errorCode: "server_error", message, raw: body };
|
|
1993
|
+
if (status === 404)
|
|
1994
|
+
return { ok: false, status, errorType: "retryable", errorCode: "model_not_found", message, raw: body };
|
|
1995
|
+
if (status === 401 || status === 403)
|
|
1996
|
+
return { ok: false, status, errorType: "terminal", errorCode: "auth", message, raw: body };
|
|
1997
|
+
if (status === 400)
|
|
1998
|
+
return { ok: false, status, errorType: "terminal", errorCode: "invalid_request", message, raw: body };
|
|
1999
|
+
return { ok: false, status, errorType: "terminal", errorCode: "unknown", message, raw: body };
|
|
2000
|
+
}
|
|
2001
|
+
function extractErrorMessage(body) {
|
|
2002
|
+
if (!body || typeof body !== "object") return void 0;
|
|
2003
|
+
const b = body;
|
|
2004
|
+
if (b.error && typeof b.error === "object") {
|
|
2005
|
+
const e = b.error;
|
|
2006
|
+
if (typeof e.message === "string") return e.message;
|
|
2007
|
+
}
|
|
2008
|
+
if (typeof b.message === "string") return b.message;
|
|
2009
|
+
return void 0;
|
|
2010
|
+
}
|
|
2011
|
+
function retryableError(status, code, message, raw) {
|
|
2012
|
+
return { ok: false, status, errorType: "retryable", errorCode: code, message, raw };
|
|
2013
|
+
}
|
|
2014
|
+
|
|
2015
|
+
// src/execute.ts
|
|
2016
|
+
var ANTHROPIC_URL2 = "https://api.anthropic.com/v1/messages";
|
|
1730
2017
|
var OPENAI_URL = "https://api.openai.com/v1/chat/completions";
|
|
1731
2018
|
var DEEPSEEK_URL = "https://api.deepseek.com/chat/completions";
|
|
1732
2019
|
async function execute(request, opts = {}) {
|
|
@@ -1751,12 +2038,18 @@ async function executeAnthropic(request, opts) {
|
|
|
1751
2038
|
if (!apiKey) {
|
|
1752
2039
|
return terminalError(401, "auth", "ANTHROPIC_API_KEY missing");
|
|
1753
2040
|
}
|
|
2041
|
+
if (opts.onChunk) {
|
|
2042
|
+
return streamAnthropic(request, apiKey, {
|
|
2043
|
+
onChunk: opts.onChunk,
|
|
2044
|
+
fetchImpl: opts.fetchImpl
|
|
2045
|
+
});
|
|
2046
|
+
}
|
|
1754
2047
|
const { provider: _provider, ...body } = request;
|
|
1755
2048
|
const fetchFn = opts.fetchImpl ?? fetch;
|
|
1756
2049
|
let res;
|
|
1757
2050
|
let json;
|
|
1758
2051
|
try {
|
|
1759
|
-
res = await fetchFn(
|
|
2052
|
+
res = await fetchFn(ANTHROPIC_URL2, {
|
|
1760
2053
|
method: "POST",
|
|
1761
2054
|
headers: {
|
|
1762
2055
|
"x-api-key": apiKey,
|
|
@@ -1767,9 +2060,9 @@ async function executeAnthropic(request, opts) {
|
|
|
1767
2060
|
});
|
|
1768
2061
|
json = await res.json().catch(() => ({}));
|
|
1769
2062
|
} catch (err) {
|
|
1770
|
-
return
|
|
2063
|
+
return retryableError2(0, "network_error", String(err), null);
|
|
1771
2064
|
}
|
|
1772
|
-
if (!res.ok) return
|
|
2065
|
+
if (!res.ok) return classifyHttpError2(res.status, json);
|
|
1773
2066
|
return { ok: true, status: res.status, response: normalizeAnthropic(json) };
|
|
1774
2067
|
}
|
|
1775
2068
|
function normalizeAnthropic(raw) {
|
|
@@ -1803,9 +2096,9 @@ async function executeGoogle(request, opts) {
|
|
|
1803
2096
|
});
|
|
1804
2097
|
json = await res.json().catch(() => ({}));
|
|
1805
2098
|
} catch (err) {
|
|
1806
|
-
return
|
|
2099
|
+
return retryableError2(0, "network_error", String(err), null);
|
|
1807
2100
|
}
|
|
1808
|
-
if (!res.ok) return
|
|
2101
|
+
if (!res.ok) return classifyHttpError2(res.status, json);
|
|
1809
2102
|
return { ok: true, status: res.status, response: normalizeGoogle(json) };
|
|
1810
2103
|
}
|
|
1811
2104
|
function normalizeGoogle(raw) {
|
|
@@ -1832,6 +2125,12 @@ async function executeOpenAI(request, opts) {
|
|
|
1832
2125
|
if (!apiKey) {
|
|
1833
2126
|
return terminalError(401, "auth", "OPENAI_API_KEY missing");
|
|
1834
2127
|
}
|
|
2128
|
+
if (opts.onChunk) {
|
|
2129
|
+
return streamOpenAILike(OPENAI_URL, request, apiKey, "openai", {
|
|
2130
|
+
onChunk: opts.onChunk,
|
|
2131
|
+
fetchImpl: opts.fetchImpl
|
|
2132
|
+
});
|
|
2133
|
+
}
|
|
1835
2134
|
const { provider: _provider, ...body } = request;
|
|
1836
2135
|
const fetchFn = opts.fetchImpl ?? fetch;
|
|
1837
2136
|
let res;
|
|
@@ -1844,9 +2143,9 @@ async function executeOpenAI(request, opts) {
|
|
|
1844
2143
|
});
|
|
1845
2144
|
json = await res.json().catch(() => ({}));
|
|
1846
2145
|
} catch (err) {
|
|
1847
|
-
return
|
|
2146
|
+
return retryableError2(0, "network_error", String(err), null);
|
|
1848
2147
|
}
|
|
1849
|
-
if (!res.ok) return
|
|
2148
|
+
if (!res.ok) return classifyHttpError2(res.status, json);
|
|
1850
2149
|
return { ok: true, status: res.status, response: normalizeOpenAILike(json) };
|
|
1851
2150
|
}
|
|
1852
2151
|
async function executeDeepSeek(request, opts) {
|
|
@@ -1854,6 +2153,12 @@ async function executeDeepSeek(request, opts) {
|
|
|
1854
2153
|
if (!apiKey) {
|
|
1855
2154
|
return terminalError(401, "auth", "DEEPSEEK_API_KEY missing");
|
|
1856
2155
|
}
|
|
2156
|
+
if (opts.onChunk) {
|
|
2157
|
+
return streamOpenAILike(DEEPSEEK_URL, request, apiKey, "deepseek", {
|
|
2158
|
+
onChunk: opts.onChunk,
|
|
2159
|
+
fetchImpl: opts.fetchImpl
|
|
2160
|
+
});
|
|
2161
|
+
}
|
|
1857
2162
|
const { provider: _provider, ...body } = request;
|
|
1858
2163
|
const fetchFn = opts.fetchImpl ?? fetch;
|
|
1859
2164
|
let res;
|
|
@@ -1866,9 +2171,9 @@ async function executeDeepSeek(request, opts) {
|
|
|
1866
2171
|
});
|
|
1867
2172
|
json = await res.json().catch(() => ({}));
|
|
1868
2173
|
} catch (err) {
|
|
1869
|
-
return
|
|
2174
|
+
return retryableError2(0, "network_error", String(err), null);
|
|
1870
2175
|
}
|
|
1871
|
-
if (!res.ok) return
|
|
2176
|
+
if (!res.ok) return classifyHttpError2(res.status, json);
|
|
1872
2177
|
return { ok: true, status: res.status, response: normalizeOpenAILike(json) };
|
|
1873
2178
|
}
|
|
1874
2179
|
function normalizeOpenAILike(raw) {
|
|
@@ -1878,7 +2183,7 @@ function normalizeOpenAILike(raw) {
|
|
|
1878
2183
|
const toolCalls = (choice?.message?.tool_calls ?? []).filter((tc) => tc.function?.name).map((tc, i) => ({
|
|
1879
2184
|
id: tc.id ?? `tc-${i}`,
|
|
1880
2185
|
name: tc.function.name,
|
|
1881
|
-
args:
|
|
2186
|
+
args: tryParseJson2(tc.function?.arguments) ?? {}
|
|
1882
2187
|
}));
|
|
1883
2188
|
const u = r.usage ?? {};
|
|
1884
2189
|
const tokens = {
|
|
@@ -1895,8 +2200,8 @@ function applyOverrides(request, overrides) {
|
|
|
1895
2200
|
if (!layer) return request;
|
|
1896
2201
|
return { ...request, ...layer };
|
|
1897
2202
|
}
|
|
1898
|
-
function
|
|
1899
|
-
const message =
|
|
2203
|
+
function classifyHttpError2(status, body) {
|
|
2204
|
+
const message = extractErrorMessage2(body) ?? `HTTP ${status}`;
|
|
1900
2205
|
if (status === 429) {
|
|
1901
2206
|
return { ok: false, status, errorType: "retryable", errorCode: "rate_limit", message, raw: body };
|
|
1902
2207
|
}
|
|
@@ -1917,7 +2222,7 @@ function classifyHttpError(status, body) {
|
|
|
1917
2222
|
}
|
|
1918
2223
|
return { ok: false, status, errorType: "terminal", errorCode: "unknown", message, raw: body };
|
|
1919
2224
|
}
|
|
1920
|
-
function
|
|
2225
|
+
function extractErrorMessage2(body) {
|
|
1921
2226
|
if (!body || typeof body !== "object") return void 0;
|
|
1922
2227
|
const b = body;
|
|
1923
2228
|
if (b.error && typeof b.error === "object") {
|
|
@@ -1930,10 +2235,10 @@ function extractErrorMessage(body) {
|
|
|
1930
2235
|
function terminalError(status, code, message) {
|
|
1931
2236
|
return { ok: false, status, errorType: "terminal", errorCode: code, message, raw: null };
|
|
1932
2237
|
}
|
|
1933
|
-
function
|
|
2238
|
+
function retryableError2(status, code, message, raw) {
|
|
1934
2239
|
return { ok: false, status, errorType: "retryable", errorCode: code, message, raw };
|
|
1935
2240
|
}
|
|
1936
|
-
function
|
|
2241
|
+
function tryParseJson2(s) {
|
|
1937
2242
|
if (typeof s !== "string" || s.length === 0) return void 0;
|
|
1938
2243
|
try {
|
|
1939
2244
|
const parsed = JSON.parse(s);
|
|
@@ -2103,10 +2408,13 @@ async function call(ir, opts = {}) {
|
|
|
2103
2408
|
safeEmit(
|
|
2104
2409
|
() => emitExecuteAttempt(traceId, ir.appId, { model: targetModel, attemptIndex: i })
|
|
2105
2410
|
);
|
|
2411
|
+
const targetSupportsStreaming = targetProfile?.streaming === true;
|
|
2412
|
+
const streamingOnChunk = opts.onChunk && !opts.noStream && targetSupportsStreaming ? opts.onChunk : void 0;
|
|
2106
2413
|
const exec = await execute(activeCompile.request, {
|
|
2107
2414
|
apiKeys: opts.apiKeys,
|
|
2108
2415
|
fetchImpl: opts.fetchImpl,
|
|
2109
|
-
providerOverrides: opts.providerOverrides
|
|
2416
|
+
providerOverrides: opts.providerOverrides,
|
|
2417
|
+
onChunk: streamingOnChunk
|
|
2110
2418
|
});
|
|
2111
2419
|
const validated = exec.ok ? validateStructuredContract(exec, ir) : exec;
|
|
2112
2420
|
if (validated.ok) {
|
|
@@ -733,6 +733,43 @@ interface CallOptions {
|
|
|
733
733
|
* for hermetic test runs.
|
|
734
734
|
*/
|
|
735
735
|
noAutoFilter?: boolean;
|
|
736
|
+
/**
|
|
737
|
+
* alpha.34. When provided AND the chosen provider supports streaming
|
|
738
|
+
* (`profile.streaming === true`) AND `noStream` is not set, kgauto
|
|
739
|
+
* enables provider-native SSE streaming at the wire layer and invokes
|
|
740
|
+
* `onChunk(delta)` once per provider stream event. `delta` is the text
|
|
741
|
+
* since the previous `onChunk` call (NOT cumulative) — provider
|
|
742
|
+
* stream-shape headache normalized in kgauto's lowering layer.
|
|
743
|
+
*
|
|
744
|
+
* `CallResult.response.text` is still populated with the full assembled
|
|
745
|
+
* response — kgauto buffers internally regardless of the callback.
|
|
746
|
+
* Consumers can use either the streaming side-effect OR the final
|
|
747
|
+
* `response.text`, doesn't matter.
|
|
748
|
+
*
|
|
749
|
+
* Tool calls + finish reason + usage are collected from stream events
|
|
750
|
+
* and returned in the final `CallResult` exactly as the non-streaming
|
|
751
|
+
* path would shape them. Brain telemetry latency = time-to-stream-end.
|
|
752
|
+
*
|
|
753
|
+
* Chain-walk semantics: if the streaming target fails mid-stream
|
|
754
|
+
* (network error, retryable provider error), kgauto walks to the next
|
|
755
|
+
* fallback target and restarts streaming from its first chunk —
|
|
756
|
+
* `onChunk` fires fresh from the new target. Consumer detects via the
|
|
757
|
+
* post-call `CallResult.fellOverFrom`. To opt out of fallback for
|
|
758
|
+
* streaming, set `noFallback: true` alongside `onChunk`.
|
|
759
|
+
*
|
|
760
|
+
* Filed by playbacksam s42 (2026-05-22) as `streaming-output-callback-
|
|
761
|
+
* on-callresult` for ComposeDrawer SSE; perceived-latency UX win
|
|
762
|
+
* during 10-30s draft assembly.
|
|
763
|
+
*/
|
|
764
|
+
onChunk?: (chunk: string) => void;
|
|
765
|
+
/**
|
|
766
|
+
* alpha.34. Explicit opt-out of streaming even when `onChunk` is
|
|
767
|
+
* provided. Default: false (streaming enabled when `onChunk` is set).
|
|
768
|
+
* Use when the consumer wants to pass `onChunk` conditionally without
|
|
769
|
+
* branching the call site (e.g., capture chunks for instrumentation
|
|
770
|
+
* without engaging streaming wire format).
|
|
771
|
+
*/
|
|
772
|
+
noStream?: boolean;
|
|
736
773
|
}
|
|
737
774
|
interface CallAttempt {
|
|
738
775
|
model: string;
|
|
@@ -733,6 +733,43 @@ interface CallOptions {
|
|
|
733
733
|
* for hermetic test runs.
|
|
734
734
|
*/
|
|
735
735
|
noAutoFilter?: boolean;
|
|
736
|
+
/**
|
|
737
|
+
* alpha.34. When provided AND the chosen provider supports streaming
|
|
738
|
+
* (`profile.streaming === true`) AND `noStream` is not set, kgauto
|
|
739
|
+
* enables provider-native SSE streaming at the wire layer and invokes
|
|
740
|
+
* `onChunk(delta)` once per provider stream event. `delta` is the text
|
|
741
|
+
* since the previous `onChunk` call (NOT cumulative) — provider
|
|
742
|
+
* stream-shape headache normalized in kgauto's lowering layer.
|
|
743
|
+
*
|
|
744
|
+
* `CallResult.response.text` is still populated with the full assembled
|
|
745
|
+
* response — kgauto buffers internally regardless of the callback.
|
|
746
|
+
* Consumers can use either the streaming side-effect OR the final
|
|
747
|
+
* `response.text`, doesn't matter.
|
|
748
|
+
*
|
|
749
|
+
* Tool calls + finish reason + usage are collected from stream events
|
|
750
|
+
* and returned in the final `CallResult` exactly as the non-streaming
|
|
751
|
+
* path would shape them. Brain telemetry latency = time-to-stream-end.
|
|
752
|
+
*
|
|
753
|
+
* Chain-walk semantics: if the streaming target fails mid-stream
|
|
754
|
+
* (network error, retryable provider error), kgauto walks to the next
|
|
755
|
+
* fallback target and restarts streaming from its first chunk —
|
|
756
|
+
* `onChunk` fires fresh from the new target. Consumer detects via the
|
|
757
|
+
* post-call `CallResult.fellOverFrom`. To opt out of fallback for
|
|
758
|
+
* streaming, set `noFallback: true` alongside `onChunk`.
|
|
759
|
+
*
|
|
760
|
+
* Filed by playbacksam s42 (2026-05-22) as `streaming-output-callback-
|
|
761
|
+
* on-callresult` for ComposeDrawer SSE; perceived-latency UX win
|
|
762
|
+
* during 10-30s draft assembly.
|
|
763
|
+
*/
|
|
764
|
+
onChunk?: (chunk: string) => void;
|
|
765
|
+
/**
|
|
766
|
+
* alpha.34. Explicit opt-out of streaming even when `onChunk` is
|
|
767
|
+
* provided. Default: false (streaming enabled when `onChunk` is set).
|
|
768
|
+
* Use when the consumer wants to pass `onChunk` conditionally without
|
|
769
|
+
* branching the call site (e.g., capture chunks for instrumentation
|
|
770
|
+
* without engaging streaming wire format).
|
|
771
|
+
*/
|
|
772
|
+
noStream?: boolean;
|
|
736
773
|
}
|
|
737
774
|
interface CallAttempt {
|
|
738
775
|
model: string;
|
package/dist/profiles.d.mts
CHANGED
package/dist/profiles.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { q as MutationApplied, B as BestPracticeAdvisory, F as FallbackReason, m as CallAttempt } from './ir-
|
|
1
|
+
import { q as MutationApplied, B as BestPracticeAdvisory, F as FallbackReason, m as CallAttempt } from './ir-BAAHLfFL.mjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Glass-Box observability types (alpha.17).
|