@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/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { C as CompilePolicy, N as NormalizedResponse, A as ApiKeys, P as ProviderOverrides, a as CompiledRequest, b as PromptIR, c as CallOptions, d as CallResult, S as SystemModelMessage, e as CompileResult, f as SectionRewrite, R as RecordInput, g as RecordOutcomeInput, O as OutcomeResult, h as OracleScore, B as BestPracticeAdvisory, i as Adapter, j as PerAxisMetrics, k as Provider, l as ChainEntry, G as Grounding } from './ir-DubC20e3.mjs';
2
- export { m as CallAttempt, n as CallError, o as ChainWithGrounding, p as Constraints, F as FallbackReason, H as HistoryCachePolicy, I as IntentDeclaration, M as Message, q as MutationApplied, r as NormalizedTokens, s as OutcomeKind, t as PerAxisMetricsByModel, u as PromptSection, v as SectionKind, T as ToolCall, w as ToolDefinition } from './ir-DubC20e3.mjs';
1
+ import { C as CompilePolicy, N as NormalizedResponse, A as ApiKeys, P as ProviderOverrides, a as CompiledRequest, b as PromptIR, c as CallOptions, d as CallResult, S as SystemModelMessage, e as CompileResult, f as SectionRewrite, R as RecordInput, g as RecordOutcomeInput, O as OutcomeResult, h as OracleScore, B as BestPracticeAdvisory, i as Adapter, j as PerAxisMetrics, k as Provider, l as ChainEntry, G as Grounding } from './ir-BAAHLfFL.mjs';
2
+ export { m as CallAttempt, n as CallError, o as ChainWithGrounding, p as Constraints, F as FallbackReason, H as HistoryCachePolicy, I as IntentDeclaration, M as Message, q as MutationApplied, r as NormalizedTokens, s as OutcomeKind, t as PerAxisMetricsByModel, u as PromptSection, v as SectionKind, T as ToolCall, w as ToolDefinition } from './ir-BAAHLfFL.mjs';
3
3
  import { ModelProfile } from './profiles.mjs';
4
4
  export { ALIASES, CacheStrategy, CliffRule, LoweringSpec, RecoveryRule, StructuredOutputCapability, SystemPromptMode, allProfiles, getProfile, profilesByProvider, tryGetProfile } from './profiles.mjs';
5
5
  import { IntentArchetypeName } from './dialect.mjs';
@@ -54,6 +54,15 @@ interface ExecuteOptions {
54
54
  apiKeys?: ApiKeys;
55
55
  fetchImpl?: typeof fetch;
56
56
  providerOverrides?: ProviderOverrides;
57
+ /**
58
+ * alpha.34. When supplied AND the chosen provider supports streaming, the
59
+ * execute() per-provider branch switches to SSE wire format and invokes
60
+ * `onChunk(delta)` once per text-delta event. Single-shot behavior
61
+ * preserved when omitted (current consumers unaffected). Wired from
62
+ * `CallOptions.onChunk` by `call()` after gating on `profile.streaming`
63
+ * and `!opts.noStream`.
64
+ */
65
+ onChunk?: (chunk: string) => void;
57
66
  }
58
67
  interface ExecuteOk {
59
68
  ok: true;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { C as CompilePolicy, N as NormalizedResponse, A as ApiKeys, P as ProviderOverrides, a as CompiledRequest, b as PromptIR, c as CallOptions, d as CallResult, S as SystemModelMessage, e as CompileResult, f as SectionRewrite, R as RecordInput, g as RecordOutcomeInput, O as OutcomeResult, h as OracleScore, B as BestPracticeAdvisory, i as Adapter, j as PerAxisMetrics, k as Provider, l as ChainEntry, G as Grounding } from './ir-GnYPkpGo.js';
2
- export { m as CallAttempt, n as CallError, o as ChainWithGrounding, p as Constraints, F as FallbackReason, H as HistoryCachePolicy, I as IntentDeclaration, M as Message, q as MutationApplied, r as NormalizedTokens, s as OutcomeKind, t as PerAxisMetricsByModel, u as PromptSection, v as SectionKind, T as ToolCall, w as ToolDefinition } from './ir-GnYPkpGo.js';
1
+ import { C as CompilePolicy, N as NormalizedResponse, A as ApiKeys, P as ProviderOverrides, a as CompiledRequest, b as PromptIR, c as CallOptions, d as CallResult, S as SystemModelMessage, e as CompileResult, f as SectionRewrite, R as RecordInput, g as RecordOutcomeInput, O as OutcomeResult, h as OracleScore, B as BestPracticeAdvisory, i as Adapter, j as PerAxisMetrics, k as Provider, l as ChainEntry, G as Grounding } from './ir-B_ygNURd.js';
2
+ export { m as CallAttempt, n as CallError, o as ChainWithGrounding, p as Constraints, F as FallbackReason, H as HistoryCachePolicy, I as IntentDeclaration, M as Message, q as MutationApplied, r as NormalizedTokens, s as OutcomeKind, t as PerAxisMetricsByModel, u as PromptSection, v as SectionKind, T as ToolCall, w as ToolDefinition } from './ir-B_ygNURd.js';
3
3
  import { ModelProfile } from './profiles.js';
4
4
  export { ALIASES, CacheStrategy, CliffRule, LoweringSpec, RecoveryRule, StructuredOutputCapability, SystemPromptMode, allProfiles, getProfile, profilesByProvider, tryGetProfile } from './profiles.js';
5
5
  import { IntentArchetypeName } from './dialect.js';
@@ -54,6 +54,15 @@ interface ExecuteOptions {
54
54
  apiKeys?: ApiKeys;
55
55
  fetchImpl?: typeof fetch;
56
56
  providerOverrides?: ProviderOverrides;
57
+ /**
58
+ * alpha.34. When supplied AND the chosen provider supports streaming, the
59
+ * execute() per-provider branch switches to SSE wire format and invokes
60
+ * `onChunk(delta)` once per text-delta event. Single-shot behavior
61
+ * preserved when omitted (current consumers unaffected). Wired from
62
+ * `CallOptions.onChunk` by `call()` after gating on `profile.streaming`
63
+ * and `!opts.noStream`.
64
+ */
65
+ onChunk?: (chunk: string) => void;
57
66
  }
58
67
  interface ExecuteOk {
59
68
  ok: true;
package/dist/index.js CHANGED
@@ -3361,8 +3361,295 @@ function getReachabilityDiagnostic(opts = {}) {
3361
3361
  return out;
3362
3362
  }
3363
3363
 
3364
- // src/execute.ts
3364
+ // src/streaming.ts
3365
3365
  var ANTHROPIC_URL = "https://api.anthropic.com/v1/messages";
3366
+ async function streamAnthropic(request, apiKey, opts) {
3367
+ const { provider: _provider, ...body } = request;
3368
+ const fetchFn = opts.fetchImpl ?? fetch;
3369
+ let res;
3370
+ try {
3371
+ res = await fetchFn(ANTHROPIC_URL, {
3372
+ method: "POST",
3373
+ headers: {
3374
+ "x-api-key": apiKey,
3375
+ "anthropic-version": "2023-06-01",
3376
+ "content-type": "application/json"
3377
+ },
3378
+ body: JSON.stringify({ ...body, stream: true })
3379
+ });
3380
+ } catch (err) {
3381
+ return retryableError(0, "network_error", String(err), null);
3382
+ }
3383
+ if (!res.ok) {
3384
+ const errBody = await res.json().catch(() => ({}));
3385
+ return classifyHttpError(res.status, errBody);
3386
+ }
3387
+ let text = "";
3388
+ let inputTokens = 0;
3389
+ let outputTokens = 0;
3390
+ let cacheReadTokens;
3391
+ let cacheCreatedTokens;
3392
+ let stopReason;
3393
+ const toolBlocks = /* @__PURE__ */ new Map();
3394
+ try {
3395
+ await parseSSEStream(res, (event) => {
3396
+ if (!event.data) return;
3397
+ let payload;
3398
+ try {
3399
+ payload = JSON.parse(event.data);
3400
+ } catch {
3401
+ return;
3402
+ }
3403
+ const type = payload.type;
3404
+ if (type === "message_start") {
3405
+ const msg = payload.message;
3406
+ const usage = msg?.usage;
3407
+ if (usage) {
3408
+ inputTokens = usage.input_tokens ?? 0;
3409
+ outputTokens = usage.output_tokens ?? 0;
3410
+ if (typeof usage.cache_read_input_tokens === "number")
3411
+ cacheReadTokens = usage.cache_read_input_tokens;
3412
+ if (typeof usage.cache_creation_input_tokens === "number")
3413
+ cacheCreatedTokens = usage.cache_creation_input_tokens;
3414
+ }
3415
+ return;
3416
+ }
3417
+ if (type === "content_block_start") {
3418
+ const p = payload;
3419
+ const idx = p.index ?? 0;
3420
+ const block = p.content_block;
3421
+ if (block?.type === "tool_use" && block.id && block.name) {
3422
+ toolBlocks.set(idx, { id: block.id, name: block.name, argsJson: "" });
3423
+ }
3424
+ return;
3425
+ }
3426
+ if (type === "content_block_delta") {
3427
+ const p = payload;
3428
+ const delta = p.delta;
3429
+ if (!delta) return;
3430
+ if (delta.type === "text_delta" && typeof delta.text === "string") {
3431
+ text += delta.text;
3432
+ opts.onChunk(delta.text);
3433
+ } else if (delta.type === "input_json_delta" && typeof delta.partial_json === "string") {
3434
+ const idx = p.index ?? 0;
3435
+ const tool = toolBlocks.get(idx);
3436
+ if (tool) tool.argsJson += delta.partial_json;
3437
+ }
3438
+ return;
3439
+ }
3440
+ if (type === "message_delta") {
3441
+ const p = payload;
3442
+ if (p.delta?.stop_reason) stopReason = p.delta.stop_reason;
3443
+ if (typeof p.usage?.output_tokens === "number") outputTokens = p.usage.output_tokens;
3444
+ return;
3445
+ }
3446
+ });
3447
+ } catch (err) {
3448
+ return retryableError(0, "stream_interrupted", String(err), null);
3449
+ }
3450
+ const toolCalls = Array.from(toolBlocks.values()).map((b) => ({
3451
+ id: b.id,
3452
+ name: b.name,
3453
+ args: tryParseJson(b.argsJson) ?? {}
3454
+ }));
3455
+ const tokens = {
3456
+ input: inputTokens,
3457
+ output: outputTokens,
3458
+ total: inputTokens + outputTokens,
3459
+ cached: cacheReadTokens,
3460
+ cacheCreated: cacheCreatedTokens
3461
+ };
3462
+ const response = {
3463
+ text,
3464
+ structuredOutput: null,
3465
+ toolCalls,
3466
+ tokens,
3467
+ finishReason: stopReason,
3468
+ raw: { streamed: true, provider: "anthropic" }
3469
+ };
3470
+ return { ok: true, status: res.status, response };
3471
+ }
3472
+ async function streamOpenAILike(url, request, apiKey, providerLabel, opts) {
3473
+ const { provider: _provider, ...body } = request;
3474
+ const fetchFn = opts.fetchImpl ?? fetch;
3475
+ const reqBody = {
3476
+ ...body,
3477
+ stream: true,
3478
+ stream_options: {
3479
+ ...body.stream_options ?? {},
3480
+ include_usage: true
3481
+ }
3482
+ };
3483
+ let res;
3484
+ try {
3485
+ res = await fetchFn(url, {
3486
+ method: "POST",
3487
+ headers: {
3488
+ authorization: `Bearer ${apiKey}`,
3489
+ "content-type": "application/json"
3490
+ },
3491
+ body: JSON.stringify(reqBody)
3492
+ });
3493
+ } catch (err) {
3494
+ return retryableError(0, "network_error", String(err), null);
3495
+ }
3496
+ if (!res.ok) {
3497
+ const errBody = await res.json().catch(() => ({}));
3498
+ return classifyHttpError(res.status, errBody);
3499
+ }
3500
+ let text = "";
3501
+ let finishReason;
3502
+ let inputTokens = 0;
3503
+ let outputTokens = 0;
3504
+ let totalTokens;
3505
+ let cachedTokens;
3506
+ const toolBuffers = /* @__PURE__ */ new Map();
3507
+ try {
3508
+ await parseSSEStream(res, (event) => {
3509
+ if (!event.data) return;
3510
+ if (event.data === "[DONE]") return;
3511
+ let payload;
3512
+ try {
3513
+ payload = JSON.parse(event.data);
3514
+ } catch {
3515
+ return;
3516
+ }
3517
+ const choices = payload.choices;
3518
+ if (choices && choices.length > 0) {
3519
+ const choice = choices[0];
3520
+ const deltaContent = choice.delta?.content;
3521
+ if (typeof deltaContent === "string" && deltaContent.length > 0) {
3522
+ text += deltaContent;
3523
+ opts.onChunk(deltaContent);
3524
+ }
3525
+ const toolDeltas = choice.delta?.tool_calls;
3526
+ if (toolDeltas) {
3527
+ for (const tcDelta of toolDeltas) {
3528
+ const idx = tcDelta.index ?? 0;
3529
+ let buf = toolBuffers.get(idx);
3530
+ if (!buf) {
3531
+ buf = { id: tcDelta.id ?? `tc-${idx}`, name: "", argsJson: "" };
3532
+ toolBuffers.set(idx, buf);
3533
+ }
3534
+ if (tcDelta.id) buf.id = tcDelta.id;
3535
+ if (tcDelta.function?.name) buf.name += tcDelta.function.name;
3536
+ if (tcDelta.function?.arguments) buf.argsJson += tcDelta.function.arguments;
3537
+ }
3538
+ }
3539
+ if (choice.finish_reason) finishReason = choice.finish_reason;
3540
+ }
3541
+ const usage = payload.usage;
3542
+ if (usage) {
3543
+ if (typeof usage.prompt_tokens === "number") inputTokens = usage.prompt_tokens;
3544
+ if (typeof usage.completion_tokens === "number") outputTokens = usage.completion_tokens;
3545
+ if (typeof usage.total_tokens === "number") totalTokens = usage.total_tokens;
3546
+ const details = usage.prompt_tokens_details;
3547
+ if (typeof details?.cached_tokens === "number") cachedTokens = details.cached_tokens;
3548
+ }
3549
+ });
3550
+ } catch (err) {
3551
+ return retryableError(0, "stream_interrupted", String(err), null);
3552
+ }
3553
+ const toolCalls = Array.from(toolBuffers.values()).filter((b) => b.name.length > 0).map((b) => ({
3554
+ id: b.id,
3555
+ name: b.name,
3556
+ args: tryParseJson(b.argsJson) ?? {}
3557
+ }));
3558
+ const tokens = {
3559
+ input: inputTokens,
3560
+ output: outputTokens,
3561
+ total: totalTokens ?? inputTokens + outputTokens,
3562
+ cached: cachedTokens
3563
+ };
3564
+ const response = {
3565
+ text,
3566
+ structuredOutput: null,
3567
+ toolCalls,
3568
+ tokens,
3569
+ finishReason,
3570
+ raw: { streamed: true, provider: providerLabel }
3571
+ };
3572
+ return { ok: true, status: res.status, response };
3573
+ }
3574
+ async function parseSSEStream(response, handler) {
3575
+ const body = response.body;
3576
+ if (!body) throw new Error("Response has no body for SSE parse");
3577
+ const reader = body.getReader();
3578
+ const decoder = new TextDecoder("utf-8");
3579
+ let buffer = "";
3580
+ for (; ; ) {
3581
+ const { value, done } = await reader.read();
3582
+ if (done) break;
3583
+ buffer += decoder.decode(value, { stream: true });
3584
+ let sep;
3585
+ while (sep = buffer.indexOf("\n\n"), sep !== -1) {
3586
+ const block = buffer.slice(0, sep);
3587
+ buffer = buffer.slice(sep + 2);
3588
+ const event = parseSSEBlock(block);
3589
+ if (event) handler(event);
3590
+ }
3591
+ }
3592
+ if (buffer.length > 0) {
3593
+ const event = parseSSEBlock(buffer);
3594
+ if (event) handler(event);
3595
+ }
3596
+ }
3597
+ function parseSSEBlock(block) {
3598
+ const lines = block.split(/\r?\n/);
3599
+ let eventName;
3600
+ const dataLines = [];
3601
+ for (const line of lines) {
3602
+ if (line.startsWith(":")) continue;
3603
+ if (line.startsWith("event:")) {
3604
+ eventName = line.slice(6).trim();
3605
+ } else if (line.startsWith("data:")) {
3606
+ dataLines.push(line.slice(5).trim());
3607
+ }
3608
+ }
3609
+ if (dataLines.length === 0) return void 0;
3610
+ return { event: eventName, data: dataLines.join("\n") };
3611
+ }
3612
+ function tryParseJson(s) {
3613
+ if (typeof s !== "string" || s.length === 0) return void 0;
3614
+ try {
3615
+ const parsed = JSON.parse(s);
3616
+ return typeof parsed === "object" && parsed !== null ? parsed : void 0;
3617
+ } catch {
3618
+ return void 0;
3619
+ }
3620
+ }
3621
+ function classifyHttpError(status, body) {
3622
+ const message = extractErrorMessage(body) ?? `HTTP ${status}`;
3623
+ if (status === 429)
3624
+ return { ok: false, status, errorType: "retryable", errorCode: "rate_limit", message, raw: body };
3625
+ if (status === 408)
3626
+ return { ok: false, status, errorType: "retryable", errorCode: "timeout", message, raw: body };
3627
+ if (status >= 500)
3628
+ return { ok: false, status, errorType: "retryable", errorCode: "server_error", message, raw: body };
3629
+ if (status === 404)
3630
+ return { ok: false, status, errorType: "retryable", errorCode: "model_not_found", message, raw: body };
3631
+ if (status === 401 || status === 403)
3632
+ return { ok: false, status, errorType: "terminal", errorCode: "auth", message, raw: body };
3633
+ if (status === 400)
3634
+ return { ok: false, status, errorType: "terminal", errorCode: "invalid_request", message, raw: body };
3635
+ return { ok: false, status, errorType: "terminal", errorCode: "unknown", message, raw: body };
3636
+ }
3637
+ function extractErrorMessage(body) {
3638
+ if (!body || typeof body !== "object") return void 0;
3639
+ const b = body;
3640
+ if (b.error && typeof b.error === "object") {
3641
+ const e = b.error;
3642
+ if (typeof e.message === "string") return e.message;
3643
+ }
3644
+ if (typeof b.message === "string") return b.message;
3645
+ return void 0;
3646
+ }
3647
+ function retryableError(status, code, message, raw) {
3648
+ return { ok: false, status, errorType: "retryable", errorCode: code, message, raw };
3649
+ }
3650
+
3651
+ // src/execute.ts
3652
+ var ANTHROPIC_URL2 = "https://api.anthropic.com/v1/messages";
3366
3653
  var OPENAI_URL = "https://api.openai.com/v1/chat/completions";
3367
3654
  var DEEPSEEK_URL = "https://api.deepseek.com/chat/completions";
3368
3655
  async function execute(request, opts = {}) {
@@ -3387,12 +3674,18 @@ async function executeAnthropic(request, opts) {
3387
3674
  if (!apiKey) {
3388
3675
  return terminalError(401, "auth", "ANTHROPIC_API_KEY missing");
3389
3676
  }
3677
+ if (opts.onChunk) {
3678
+ return streamAnthropic(request, apiKey, {
3679
+ onChunk: opts.onChunk,
3680
+ fetchImpl: opts.fetchImpl
3681
+ });
3682
+ }
3390
3683
  const { provider: _provider, ...body } = request;
3391
3684
  const fetchFn = opts.fetchImpl ?? fetch;
3392
3685
  let res;
3393
3686
  let json;
3394
3687
  try {
3395
- res = await fetchFn(ANTHROPIC_URL, {
3688
+ res = await fetchFn(ANTHROPIC_URL2, {
3396
3689
  method: "POST",
3397
3690
  headers: {
3398
3691
  "x-api-key": apiKey,
@@ -3403,9 +3696,9 @@ async function executeAnthropic(request, opts) {
3403
3696
  });
3404
3697
  json = await res.json().catch(() => ({}));
3405
3698
  } catch (err) {
3406
- return retryableError(0, "network_error", String(err), null);
3699
+ return retryableError2(0, "network_error", String(err), null);
3407
3700
  }
3408
- if (!res.ok) return classifyHttpError(res.status, json);
3701
+ if (!res.ok) return classifyHttpError2(res.status, json);
3409
3702
  return { ok: true, status: res.status, response: normalizeAnthropic(json) };
3410
3703
  }
3411
3704
  function normalizeAnthropic(raw) {
@@ -3439,9 +3732,9 @@ async function executeGoogle(request, opts) {
3439
3732
  });
3440
3733
  json = await res.json().catch(() => ({}));
3441
3734
  } catch (err) {
3442
- return retryableError(0, "network_error", String(err), null);
3735
+ return retryableError2(0, "network_error", String(err), null);
3443
3736
  }
3444
- if (!res.ok) return classifyHttpError(res.status, json);
3737
+ if (!res.ok) return classifyHttpError2(res.status, json);
3445
3738
  return { ok: true, status: res.status, response: normalizeGoogle(json) };
3446
3739
  }
3447
3740
  function normalizeGoogle(raw) {
@@ -3468,6 +3761,12 @@ async function executeOpenAI(request, opts) {
3468
3761
  if (!apiKey) {
3469
3762
  return terminalError(401, "auth", "OPENAI_API_KEY missing");
3470
3763
  }
3764
+ if (opts.onChunk) {
3765
+ return streamOpenAILike(OPENAI_URL, request, apiKey, "openai", {
3766
+ onChunk: opts.onChunk,
3767
+ fetchImpl: opts.fetchImpl
3768
+ });
3769
+ }
3471
3770
  const { provider: _provider, ...body } = request;
3472
3771
  const fetchFn = opts.fetchImpl ?? fetch;
3473
3772
  let res;
@@ -3480,9 +3779,9 @@ async function executeOpenAI(request, opts) {
3480
3779
  });
3481
3780
  json = await res.json().catch(() => ({}));
3482
3781
  } catch (err) {
3483
- return retryableError(0, "network_error", String(err), null);
3782
+ return retryableError2(0, "network_error", String(err), null);
3484
3783
  }
3485
- if (!res.ok) return classifyHttpError(res.status, json);
3784
+ if (!res.ok) return classifyHttpError2(res.status, json);
3486
3785
  return { ok: true, status: res.status, response: normalizeOpenAILike(json) };
3487
3786
  }
3488
3787
  async function executeDeepSeek(request, opts) {
@@ -3490,6 +3789,12 @@ async function executeDeepSeek(request, opts) {
3490
3789
  if (!apiKey) {
3491
3790
  return terminalError(401, "auth", "DEEPSEEK_API_KEY missing");
3492
3791
  }
3792
+ if (opts.onChunk) {
3793
+ return streamOpenAILike(DEEPSEEK_URL, request, apiKey, "deepseek", {
3794
+ onChunk: opts.onChunk,
3795
+ fetchImpl: opts.fetchImpl
3796
+ });
3797
+ }
3493
3798
  const { provider: _provider, ...body } = request;
3494
3799
  const fetchFn = opts.fetchImpl ?? fetch;
3495
3800
  let res;
@@ -3502,9 +3807,9 @@ async function executeDeepSeek(request, opts) {
3502
3807
  });
3503
3808
  json = await res.json().catch(() => ({}));
3504
3809
  } catch (err) {
3505
- return retryableError(0, "network_error", String(err), null);
3810
+ return retryableError2(0, "network_error", String(err), null);
3506
3811
  }
3507
- if (!res.ok) return classifyHttpError(res.status, json);
3812
+ if (!res.ok) return classifyHttpError2(res.status, json);
3508
3813
  return { ok: true, status: res.status, response: normalizeOpenAILike(json) };
3509
3814
  }
3510
3815
  function normalizeOpenAILike(raw) {
@@ -3514,7 +3819,7 @@ function normalizeOpenAILike(raw) {
3514
3819
  const toolCalls = (choice?.message?.tool_calls ?? []).filter((tc) => tc.function?.name).map((tc, i) => ({
3515
3820
  id: tc.id ?? `tc-${i}`,
3516
3821
  name: tc.function.name,
3517
- args: tryParseJson(tc.function?.arguments) ?? {}
3822
+ args: tryParseJson2(tc.function?.arguments) ?? {}
3518
3823
  }));
3519
3824
  const u = r.usage ?? {};
3520
3825
  const tokens = {
@@ -3531,8 +3836,8 @@ function applyOverrides(request, overrides) {
3531
3836
  if (!layer) return request;
3532
3837
  return { ...request, ...layer };
3533
3838
  }
3534
- function classifyHttpError(status, body) {
3535
- const message = extractErrorMessage(body) ?? `HTTP ${status}`;
3839
+ function classifyHttpError2(status, body) {
3840
+ const message = extractErrorMessage2(body) ?? `HTTP ${status}`;
3536
3841
  if (status === 429) {
3537
3842
  return { ok: false, status, errorType: "retryable", errorCode: "rate_limit", message, raw: body };
3538
3843
  }
@@ -3553,7 +3858,7 @@ function classifyHttpError(status, body) {
3553
3858
  }
3554
3859
  return { ok: false, status, errorType: "terminal", errorCode: "unknown", message, raw: body };
3555
3860
  }
3556
- function extractErrorMessage(body) {
3861
+ function extractErrorMessage2(body) {
3557
3862
  if (!body || typeof body !== "object") return void 0;
3558
3863
  const b = body;
3559
3864
  if (b.error && typeof b.error === "object") {
@@ -3566,10 +3871,10 @@ function extractErrorMessage(body) {
3566
3871
  function terminalError(status, code, message) {
3567
3872
  return { ok: false, status, errorType: "terminal", errorCode: code, message, raw: null };
3568
3873
  }
3569
- function retryableError(status, code, message, raw) {
3874
+ function retryableError2(status, code, message, raw) {
3570
3875
  return { ok: false, status, errorType: "retryable", errorCode: code, message, raw };
3571
3876
  }
3572
- function tryParseJson(s) {
3877
+ function tryParseJson2(s) {
3573
3878
  if (typeof s !== "string" || s.length === 0) return void 0;
3574
3879
  try {
3575
3880
  const parsed = JSON.parse(s);
@@ -4383,10 +4688,13 @@ async function call(ir, opts = {}) {
4383
4688
  safeEmit(
4384
4689
  () => emitExecuteAttempt(traceId, ir.appId, { model: targetModel, attemptIndex: i })
4385
4690
  );
4691
+ const targetSupportsStreaming = targetProfile?.streaming === true;
4692
+ const streamingOnChunk = opts.onChunk && !opts.noStream && targetSupportsStreaming ? opts.onChunk : void 0;
4386
4693
  const exec = await execute(activeCompile.request, {
4387
4694
  apiKeys: opts.apiKeys,
4388
4695
  fetchImpl: opts.fetchImpl,
4389
- providerOverrides: opts.providerOverrides
4696
+ providerOverrides: opts.providerOverrides,
4697
+ onChunk: streamingOnChunk
4390
4698
  });
4391
4699
  const validated = exec.ok ? validateStructuredContract(exec, ir) : exec;
4392
4700
  if (validated.ok) {