@theokit/agents 0.45.0 → 0.46.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.
@@ -562,9 +562,14 @@ function compileAgentDefinition(def) {
562
562
  ...def.settingSources !== void 0 ? {
563
563
  settingSources: def.settingSources
564
564
  } : {},
565
- ...def.plugins !== void 0 ? {
566
- plugins: def.plugins
565
+ // M49 memory flows to the projection layer; `assembleM8CreateOptions` forwards it to Agent.create.
566
+ ...def.memory !== void 0 ? {
567
+ memory: def.memory
567
568
  } : {},
569
+ // Hooks are converted here — the layer EVERY path converges on — rather than on the builder, so
570
+ // `defineAgent({ hooks })` cannot type-check and silently no-op. A lifecycle hook that is
571
+ // declared but never registered is a security gate that does not gate.
572
+ ...compileHooksAndPlugins(def),
568
573
  // MCP — builder/`defineAgent` servers converge on the same `mcpServers` field the `@MCP`
569
574
  // decorator path populates; the SDK adapter forwards it to `Agent.create({ mcpServers })`.
570
575
  ...def.mcpServers !== void 0 ? {
@@ -573,6 +578,33 @@ function compileAgentDefinition(def) {
573
578
  };
574
579
  }
575
580
  __name(compileAgentDefinition, "compileAgentDefinition");
581
+ function compileHooksAndPlugins(def) {
582
+ const map = def.hooks;
583
+ const entries = Object.entries(map ?? {}).filter(([, h]) => typeof h === "function");
584
+ const explicit = def.plugins ?? [];
585
+ if (entries.length === 0) {
586
+ return def.plugins !== void 0 ? {
587
+ plugins: def.plugins
588
+ } : {};
589
+ }
590
+ const plugin = {
591
+ name: "theokit-builder-hooks",
592
+ version: "1.0.0",
593
+ kind: "general",
594
+ register(ctx) {
595
+ for (const [hookName, handler] of entries) {
596
+ ctx.on(hookName, handler);
597
+ }
598
+ }
599
+ };
600
+ return {
601
+ plugins: [
602
+ ...explicit,
603
+ plugin
604
+ ]
605
+ };
606
+ }
607
+ __name(compileHooksAndPlugins, "compileHooksAndPlugins");
576
608
  function compileSkillsSelection(skills) {
577
609
  if (skills === void 0) return {};
578
610
  if (typeof skills === "function") return {
@@ -952,6 +984,21 @@ function assembleM8CreateOptions(compiled) {
952
984
  options.mcpServers = compiled.mcpServers;
953
985
  applied.push("mcpServers");
954
986
  }
987
+ if (compiled.memory !== void 0) {
988
+ if ("enabled" in compiled.memory) {
989
+ options.memory = compiled.memory;
990
+ } else {
991
+ const dropped = Object.keys(compiled.memory);
992
+ if (dropped.length > 0) {
993
+ process.stderr.write(`[theokit-agents] @Memory decorator options not yet mapped to the SDK (${dropped.join(", ")}) \u2014 memory enabled with defaults
994
+ `);
995
+ }
996
+ options.memory = {
997
+ enabled: true
998
+ };
999
+ }
1000
+ applied.push("memory");
1001
+ }
955
1002
  return {
956
1003
  options,
957
1004
  applied
@@ -1397,7 +1444,11 @@ async function* streamSdkAgent(rt, compiled, sdkTools, opts) {
1397
1444
  onDelta
1398
1445
  };
1399
1446
  if (factoryOpts?.disableTools === true) sendOptions.toolChoice = "none";
1400
- const sendPromise = agent2.send(message, sendOptions);
1447
+ const sendInput = overrides.images && overrides.images.length > 0 ? {
1448
+ text: message,
1449
+ images: overrides.images
1450
+ } : message;
1451
+ const sendPromise = agent2.send(sendInput, sendOptions);
1401
1452
  const openStream = /* @__PURE__ */ __name(async () => (await sendPromise).stream(), "openStream");
1402
1453
  const merged = mergeDeltaStream(queue, openStream, runId, state);
1403
1454
  for await (const event of applyTextTransforms(merged, {
@@ -1452,160 +1503,507 @@ function toAgentFactory(def, opts) {
1452
1503
  }
1453
1504
  __name(toAgentFactory, "toAgentFactory");
1454
1505
 
1455
- // src/bridge/ui-message-stream-translator.ts
1456
- function* closeOpenBlock(state, textId) {
1457
- if (state.openBlock === "text") {
1458
- yield {
1459
- type: "text-end",
1460
- id: textId
1461
- };
1462
- } else if (state.openBlock === "reasoning" && state.reasoningId) {
1463
- yield {
1464
- type: "reasoning-end",
1465
- id: state.reasoningId
1466
- };
1506
+ // ../presenter/dist/index.js
1507
+ var __defProp = Object.defineProperty;
1508
+ var __name2 = /* @__PURE__ */ __name((target, value) => __defProp(target, "name", {
1509
+ value,
1510
+ configurable: true
1511
+ }), "__name");
1512
+ var UnknownPresenterError = class extends Error {
1513
+ static {
1514
+ __name(this, "UnknownPresenterError");
1515
+ }
1516
+ static {
1517
+ __name2(this, "UnknownPresenterError");
1518
+ }
1519
+ name = "UnknownPresenterError";
1520
+ constructor(surface, known) {
1521
+ super(`No presenter registered for surface "${surface}". Known: ${known.join(", ") || "(none)"}.`);
1522
+ }
1523
+ };
1524
+ var PresenterRegistry = class {
1525
+ static {
1526
+ __name(this, "PresenterRegistry");
1527
+ }
1528
+ static {
1529
+ __name2(this, "PresenterRegistry");
1530
+ }
1531
+ #presenters = /* @__PURE__ */ new Map();
1532
+ /** Register (or replace) the presenter for its surface. Returns `this` for fluent wiring. */
1533
+ register(presenter) {
1534
+ this.#presenters.set(presenter.surface, presenter);
1535
+ return this;
1536
+ }
1537
+ /** Whether a presenter is registered for `surface`. */
1538
+ has(surface) {
1539
+ return this.#presenters.has(surface);
1540
+ }
1541
+ /** The registered surface keys. */
1542
+ surfaces() {
1543
+ return [
1544
+ ...this.#presenters.keys()
1545
+ ];
1467
1546
  }
1468
- state.openBlock = null;
1469
- state.reasoningId = null;
1547
+ /** Resolve the presenter for `surface`, or throw {@link UnknownPresenterError} (never returns undefined). */
1548
+ resolve(surface) {
1549
+ const p = this.#presenters.get(surface);
1550
+ if (p === void 0) throw new UnknownPresenterError(surface, this.surfaces());
1551
+ return p;
1552
+ }
1553
+ };
1554
+ function asString2(value, fallback) {
1555
+ return typeof value === "string" ? value : fallback;
1470
1556
  }
1471
- __name(closeOpenBlock, "closeOpenBlock");
1472
- function* emitTextDelta(state, textId, content) {
1473
- if (state.openBlock !== "text") {
1474
- yield* closeOpenBlock(state, textId);
1475
- yield {
1476
- type: "text-start",
1477
- id: textId
1478
- };
1479
- state.openBlock = "text";
1557
+ __name(asString2, "asString");
1558
+ __name2(asString2, "asString");
1559
+ function serializeToolResult(value, fallback) {
1560
+ if (typeof value === "string") return value;
1561
+ if (value === void 0 || value === null) return fallback;
1562
+ try {
1563
+ return JSON.stringify(value);
1564
+ } catch {
1565
+ return typeof value === "bigint" ? value.toString() : fallback;
1480
1566
  }
1481
- yield {
1482
- type: "text-delta",
1483
- id: textId,
1484
- delta: content
1485
- };
1486
1567
  }
1487
- __name(emitTextDelta, "emitTextDelta");
1488
- function* emitReasoningDelta(state, textId, content) {
1489
- let reasoningId = state.openBlock === "reasoning" ? state.reasoningId : null;
1490
- if (reasoningId === null) {
1491
- yield* closeOpenBlock(state, textId);
1492
- reasoningId = crypto.randomUUID();
1493
- state.reasoningId = reasoningId;
1494
- yield {
1495
- type: "reasoning-start",
1496
- id: reasoningId
1497
- };
1498
- state.openBlock = "reasoning";
1568
+ __name(serializeToolResult, "serializeToolResult");
1569
+ __name2(serializeToolResult, "serializeToolResult");
1570
+ function fromAssistant(msg) {
1571
+ const events = [];
1572
+ const content = msg.message?.content;
1573
+ if (!Array.isArray(content)) return events;
1574
+ for (const block of content) {
1575
+ const b = block;
1576
+ if (b.type === "text" && b.text) events.push({
1577
+ type: "text",
1578
+ text: b.text
1579
+ });
1580
+ if (b.type === "tool_use") {
1581
+ events.push({
1582
+ type: "tool-call",
1583
+ callId: b.id ?? `tc-${Date.now()}`,
1584
+ name: b.name ?? "unknown",
1585
+ input: b.input ?? {}
1586
+ });
1587
+ }
1499
1588
  }
1500
- yield {
1501
- type: "reasoning-delta",
1502
- id: reasoningId,
1503
- delta: content
1504
- };
1589
+ return events;
1505
1590
  }
1506
- __name(emitReasoningDelta, "emitReasoningDelta");
1507
- function* emitToolCall(event, seen) {
1508
- seen.add(event.callId);
1509
- yield {
1510
- type: "tool-input-available",
1511
- toolCallId: event.callId,
1512
- toolName: event.toolName,
1513
- input: event.input,
1514
- dynamic: true
1515
- };
1591
+ __name(fromAssistant, "fromAssistant");
1592
+ __name2(fromAssistant, "fromAssistant");
1593
+ function fromToolUse(msg) {
1594
+ const status = msg.status;
1595
+ const callId = asString2(msg.call_id, `tc-${Date.now()}`);
1596
+ const name = asString2(msg.name, "unknown");
1597
+ if (status === "completed") {
1598
+ return [
1599
+ {
1600
+ type: "tool-result",
1601
+ callId,
1602
+ name,
1603
+ result: serializeToolResult(msg.result, ""),
1604
+ isError: false
1605
+ }
1606
+ ];
1607
+ }
1608
+ if (status === "error") {
1609
+ return [
1610
+ {
1611
+ type: "tool-result",
1612
+ callId,
1613
+ name,
1614
+ result: serializeToolResult(msg.result, "Tool failed"),
1615
+ isError: true
1616
+ }
1617
+ ];
1618
+ }
1619
+ if (status === "running") {
1620
+ return [
1621
+ {
1622
+ type: "tool-call",
1623
+ callId,
1624
+ name,
1625
+ input: msg.args ?? msg.input ?? msg.arguments ?? {}
1626
+ }
1627
+ ];
1628
+ }
1629
+ return [];
1516
1630
  }
1517
- __name(emitToolCall, "emitToolCall");
1518
- function* emitToolResult(event, seen) {
1519
- if (!seen.has(event.callId)) {
1520
- seen.add(event.callId);
1521
- yield {
1522
- type: "tool-input-available",
1523
- toolCallId: event.callId,
1524
- toolName: event.toolName,
1525
- input: {},
1526
- dynamic: true
1527
- };
1631
+ __name(fromToolUse, "fromToolUse");
1632
+ __name2(fromToolUse, "fromToolUse");
1633
+ function fromStatus(msg) {
1634
+ const s = msg.status;
1635
+ if (s === "FINISHED" || s === "CANCELLED") return [
1636
+ {
1637
+ type: "finish",
1638
+ reason: s.toLowerCase()
1639
+ }
1640
+ ];
1641
+ if (s === "ERROR" || s === "EXPIRED") {
1642
+ return [
1643
+ {
1644
+ type: "error",
1645
+ message: asString2(msg.message, "Agent error"),
1646
+ code: "AGENT_ERROR"
1647
+ }
1648
+ ];
1528
1649
  }
1529
- if (event.isError) {
1530
- yield {
1531
- type: "tool-output-error",
1532
- toolCallId: event.callId,
1533
- errorText: event.output
1534
- };
1535
- } else {
1536
- yield {
1537
- type: "tool-output-available",
1538
- toolCallId: event.callId,
1539
- output: event.output
1540
- };
1650
+ return [];
1651
+ }
1652
+ __name(fromStatus, "fromStatus");
1653
+ __name2(fromStatus, "fromStatus");
1654
+ function fromSdkMessage(msg) {
1655
+ switch (msg.type) {
1656
+ case "assistant":
1657
+ return fromAssistant(msg);
1658
+ case "tool_call":
1659
+ return fromToolUse(msg);
1660
+ case "thinking":
1661
+ return [
1662
+ {
1663
+ type: "reasoning",
1664
+ text: asString2(msg.text, "")
1665
+ }
1666
+ ];
1667
+ case "status":
1668
+ return fromStatus(msg);
1669
+ // `system` / run-lifecycle is framework framing, not pure output — intentionally skipped (ADR-4).
1670
+ default:
1671
+ return [];
1541
1672
  }
1542
1673
  }
1543
- __name(emitToolResult, "emitToolResult");
1544
- function* emitApprovalRequest(event, seen) {
1545
- if (!seen.has(event.callId)) {
1546
- seen.add(event.callId);
1547
- yield {
1548
- type: "tool-input-available",
1549
- toolCallId: event.callId,
1550
- toolName: event.toolName,
1551
- input: event.input ?? {},
1552
- dynamic: true
1553
- };
1674
+ __name(fromSdkMessage, "fromSdkMessage");
1675
+ __name2(fromSdkMessage, "fromSdkMessage");
1676
+ function fromInteractionUpdate(update) {
1677
+ switch (update.type) {
1678
+ case "text-delta":
1679
+ return update.text ? [
1680
+ {
1681
+ type: "text",
1682
+ text: update.text
1683
+ }
1684
+ ] : [];
1685
+ case "thinking-delta":
1686
+ return update.text ? [
1687
+ {
1688
+ type: "reasoning",
1689
+ text: update.text
1690
+ }
1691
+ ] : [];
1692
+ case "tool-call-started":
1693
+ return [
1694
+ {
1695
+ type: "tool-call",
1696
+ callId: update.callId,
1697
+ name: update.toolCall.name,
1698
+ input: update.toolCall.args ?? {}
1699
+ }
1700
+ ];
1701
+ case "partial-tool-call":
1702
+ return [
1703
+ {
1704
+ type: "partial-tool-call",
1705
+ callId: update.callId,
1706
+ name: update.toolCall.name,
1707
+ input: update.toolCall.args ?? {}
1708
+ }
1709
+ ];
1710
+ case "tool-call-completed":
1711
+ return [
1712
+ {
1713
+ type: "tool-result",
1714
+ callId: update.callId,
1715
+ name: update.toolCall.name,
1716
+ result: serializeToolResult(update.toolCall.result, ""),
1717
+ isError: false
1718
+ }
1719
+ ];
1720
+ default:
1721
+ return [];
1554
1722
  }
1555
- yield {
1556
- type: "tool-approval-request",
1557
- approvalId: event.callId,
1558
- toolCallId: event.callId
1559
- };
1560
1723
  }
1561
- __name(emitApprovalRequest, "emitApprovalRequest");
1562
- function* emitCheckpointSaved(event) {
1563
- yield {
1564
- type: "data-checkpoint",
1565
- data: {
1566
- checkpointId: event.checkpointId,
1567
- resumeToken: event.resumeToken,
1568
- step: event.step
1569
- },
1570
- transient: true
1724
+ __name(fromInteractionUpdate, "fromInteractionUpdate");
1725
+ __name2(fromInteractionUpdate, "fromInteractionUpdate");
1726
+ var UIMessageStreamPresenter = class {
1727
+ static {
1728
+ __name(this, "UIMessageStreamPresenter");
1729
+ }
1730
+ static {
1731
+ __name2(this, "UIMessageStreamPresenter");
1732
+ }
1733
+ surface = "ui-message-stream";
1734
+ #textId;
1735
+ #openBlock = null;
1736
+ #reasoningId = null;
1737
+ #seen = /* @__PURE__ */ new Set();
1738
+ constructor(options) {
1739
+ this.#textId = options.textId;
1740
+ }
1741
+ /** Emit the opening `start` chunk (exactly once, before any event). */
1742
+ start() {
1743
+ return [
1744
+ {
1745
+ type: "start"
1746
+ }
1747
+ ];
1748
+ }
1749
+ present(event) {
1750
+ switch (event.type) {
1751
+ case "text":
1752
+ return this.#emitTextDelta(event.text);
1753
+ case "reasoning":
1754
+ return this.#emitReasoningDelta(event.text);
1755
+ case "tool-call":
1756
+ return [
1757
+ ...this.#closeOpenBlock(),
1758
+ ...this.#emitToolCall(event.callId, event.name, event.input)
1759
+ ];
1760
+ case "tool-result":
1761
+ return [
1762
+ ...this.#closeOpenBlock(),
1763
+ ...this.#emitToolResult(event.callId, event.name, event.result, event.isError ?? false)
1764
+ ];
1765
+ case "error":
1766
+ return [
1767
+ {
1768
+ type: "error",
1769
+ errorText: event.message
1770
+ }
1771
+ ];
1772
+ // `partial-tool-call` streams incremental args — the current web path emits no chunk for it
1773
+ // (args are shown on the committed `tool-call`); `finish` / `status` are handled by finish()/host.
1774
+ default:
1775
+ return [];
1776
+ }
1777
+ }
1778
+ /**
1779
+ * Close any open text/reasoning block and emit the terminal `finish` chunk. When `metadata` is given
1780
+ * (a clean run's turn totals from the framework `done`), it rides `messageMetadata`; otherwise the
1781
+ * finish is bare (error/abort turns), byte-identical to the original translator.
1782
+ */
1783
+ finish(metadata) {
1784
+ const out = this.#closeOpenBlock();
1785
+ out.push(metadata ? {
1786
+ type: "finish",
1787
+ messageMetadata: metadata
1788
+ } : {
1789
+ type: "finish"
1790
+ });
1791
+ return out;
1792
+ }
1793
+ /**
1794
+ * Close any open text/reasoning block WITHOUT finishing the stream. The host calls this before
1795
+ * interleaving a framework chunk (HITL approval / checkpoint) that must not appear inside an open text
1796
+ * block — mirroring the original translator's `closeOpenBlock` before those chunks. Idempotent.
1797
+ */
1798
+ closeBlock() {
1799
+ return this.#closeOpenBlock();
1800
+ }
1801
+ /**
1802
+ * Whether a `callId` has already been introduced (a `tool-call` or a synthesized `tool-input`). The host
1803
+ * uses this so a framework `approval_required` reuses the EC-1 synthesize-input-first rule exactly once.
1804
+ */
1805
+ hasSeen(callId) {
1806
+ return this.#seen.has(callId);
1807
+ }
1808
+ /** Mark a `callId` as introduced (the host synthesized its `tool-input` for a framework chunk). */
1809
+ markSeen(callId) {
1810
+ this.#seen.add(callId);
1811
+ }
1812
+ // --- internal open-block state machine (verbatim from the original translator) ---
1813
+ #closeOpenBlock() {
1814
+ const out = [];
1815
+ if (this.#openBlock === "text") {
1816
+ out.push({
1817
+ type: "text-end",
1818
+ id: this.#textId
1819
+ });
1820
+ } else if (this.#openBlock === "reasoning" && this.#reasoningId) {
1821
+ out.push({
1822
+ type: "reasoning-end",
1823
+ id: this.#reasoningId
1824
+ });
1825
+ }
1826
+ this.#openBlock = null;
1827
+ this.#reasoningId = null;
1828
+ return out;
1829
+ }
1830
+ #emitTextDelta(content) {
1831
+ const out = [];
1832
+ if (this.#openBlock !== "text") {
1833
+ out.push(...this.#closeOpenBlock(), {
1834
+ type: "text-start",
1835
+ id: this.#textId
1836
+ });
1837
+ this.#openBlock = "text";
1838
+ }
1839
+ out.push({
1840
+ type: "text-delta",
1841
+ id: this.#textId,
1842
+ delta: content
1843
+ });
1844
+ return out;
1845
+ }
1846
+ #emitReasoningDelta(content) {
1847
+ const out = [];
1848
+ let reasoningId = this.#openBlock === "reasoning" ? this.#reasoningId : null;
1849
+ if (reasoningId === null) {
1850
+ out.push(...this.#closeOpenBlock());
1851
+ reasoningId = crypto.randomUUID();
1852
+ this.#reasoningId = reasoningId;
1853
+ out.push({
1854
+ type: "reasoning-start",
1855
+ id: reasoningId
1856
+ });
1857
+ this.#openBlock = "reasoning";
1858
+ }
1859
+ out.push({
1860
+ type: "reasoning-delta",
1861
+ id: reasoningId,
1862
+ delta: content
1863
+ });
1864
+ return out;
1865
+ }
1866
+ #emitToolCall(callId, name, input) {
1867
+ this.#seen.add(callId);
1868
+ return [
1869
+ {
1870
+ type: "tool-input-available",
1871
+ toolCallId: callId,
1872
+ toolName: name,
1873
+ input,
1874
+ dynamic: true
1875
+ }
1876
+ ];
1877
+ }
1878
+ #emitToolResult(callId, name, result, isError2) {
1879
+ const out = [];
1880
+ if (!this.#seen.has(callId)) {
1881
+ this.#seen.add(callId);
1882
+ out.push({
1883
+ type: "tool-input-available",
1884
+ toolCallId: callId,
1885
+ toolName: name,
1886
+ input: {},
1887
+ dynamic: true
1888
+ });
1889
+ }
1890
+ const output = typeof result === "string" ? result : "";
1891
+ if (isError2) {
1892
+ out.push({
1893
+ type: "tool-output-error",
1894
+ toolCallId: callId,
1895
+ errorText: output
1896
+ });
1897
+ } else {
1898
+ out.push({
1899
+ type: "tool-output-available",
1900
+ toolCallId: callId,
1901
+ output
1902
+ });
1903
+ }
1904
+ return out;
1905
+ }
1906
+ };
1907
+
1908
+ // src/bridge/present-ui-message-stream.ts
1909
+ function toAgentOutputEvent(e) {
1910
+ switch (e.type) {
1911
+ case "text_delta":
1912
+ return {
1913
+ type: "text",
1914
+ text: e.content
1915
+ };
1916
+ case "thinking":
1917
+ return {
1918
+ type: "reasoning",
1919
+ text: e.content
1920
+ };
1921
+ case "tool_call":
1922
+ return {
1923
+ type: "tool-call",
1924
+ callId: e.callId,
1925
+ name: e.toolName,
1926
+ input: e.input
1927
+ };
1928
+ case "tool_result":
1929
+ return {
1930
+ type: "tool-result",
1931
+ callId: e.callId,
1932
+ name: e.toolName,
1933
+ result: e.output,
1934
+ isError: e.isError
1935
+ };
1936
+ default:
1937
+ return null;
1938
+ }
1939
+ }
1940
+ __name(toAgentOutputEvent, "toAgentOutputEvent");
1941
+ function doneToMetadata(event) {
1942
+ return event.cost === void 0 ? {
1943
+ usage: event.usage,
1944
+ durationMs: event.durationMs
1945
+ } : {
1946
+ usage: event.usage,
1947
+ durationMs: event.durationMs,
1948
+ cost: event.cost
1571
1949
  };
1572
1950
  }
1573
- __name(emitCheckpointSaved, "emitCheckpointSaved");
1574
- async function* translateToUIMessageStream(events, opts) {
1951
+ __name(doneToMetadata, "doneToMetadata");
1952
+ async function* presentUIMessageStream(events, opts) {
1953
+ const presenter = new UIMessageStreamPresenter({
1954
+ textId: opts.textId
1955
+ });
1575
1956
  yield {
1576
1957
  type: "start"
1577
1958
  };
1578
- const state = {
1579
- openBlock: null,
1580
- reasoningId: null
1581
- };
1582
- const seenToolCallIds = /* @__PURE__ */ new Set();
1583
1959
  let turnMetadata;
1584
1960
  try {
1585
1961
  for await (const event of events) {
1586
- if (event.type === "text_delta") {
1587
- yield* emitTextDelta(state, opts.textId, event.content);
1588
- } else if (event.type === "thinking") {
1589
- yield* emitReasoningDelta(state, opts.textId, event.content);
1590
- } else if (event.type === "tool_call") {
1591
- yield* closeOpenBlock(state, opts.textId);
1592
- yield* emitToolCall(event, seenToolCallIds);
1593
- } else if (event.type === "approval_required") {
1594
- yield* closeOpenBlock(state, opts.textId);
1595
- yield* emitApprovalRequest(event, seenToolCallIds);
1596
- } else if (event.type === "tool_result") {
1597
- yield* closeOpenBlock(state, opts.textId);
1598
- yield* emitToolResult(event, seenToolCallIds);
1599
- } else if (event.type === "checkpoint_saved") {
1600
- yield* closeOpenBlock(state, opts.textId);
1601
- yield* emitCheckpointSaved(event);
1602
- } else if (event.type === "error") {
1962
+ const output = toAgentOutputEvent(event);
1963
+ if (output !== null) {
1964
+ yield* presenter.present(output);
1965
+ continue;
1966
+ }
1967
+ if (event.type === "approval_required") {
1968
+ yield* presenter.closeBlock();
1969
+ if (!presenter.hasSeen(event.callId)) {
1970
+ presenter.markSeen(event.callId);
1971
+ yield {
1972
+ type: "tool-input-available",
1973
+ toolCallId: event.callId,
1974
+ toolName: event.toolName,
1975
+ input: event.input ?? {},
1976
+ dynamic: true
1977
+ };
1978
+ }
1979
+ yield {
1980
+ type: "tool-approval-request",
1981
+ approvalId: event.callId,
1982
+ toolCallId: event.callId
1983
+ };
1984
+ continue;
1985
+ }
1986
+ if (event.type === "checkpoint_saved") {
1987
+ yield* presenter.closeBlock();
1988
+ yield {
1989
+ type: "data-checkpoint",
1990
+ data: {
1991
+ checkpointId: event.checkpointId,
1992
+ resumeToken: event.resumeToken,
1993
+ step: event.step
1994
+ },
1995
+ transient: true
1996
+ };
1997
+ continue;
1998
+ }
1999
+ if (event.type === "error") {
1603
2000
  yield {
1604
2001
  type: "error",
1605
2002
  errorText: event.message
1606
2003
  };
1607
2004
  break;
1608
- } else if (event.type === "done") {
2005
+ }
2006
+ if (event.type === "done") {
1609
2007
  turnMetadata = doneToMetadata(event);
1610
2008
  break;
1611
2009
  }
@@ -1616,26 +2014,9 @@ async function* translateToUIMessageStream(events, opts) {
1616
2014
  errorText: String(err)
1617
2015
  };
1618
2016
  }
1619
- yield* closeOpenBlock(state, opts.textId);
1620
- yield turnMetadata ? {
1621
- type: "finish",
1622
- messageMetadata: turnMetadata
1623
- } : {
1624
- type: "finish"
1625
- };
2017
+ yield* presenter.finish(turnMetadata);
1626
2018
  }
1627
- __name(translateToUIMessageStream, "translateToUIMessageStream");
1628
- function doneToMetadata(event) {
1629
- return event.cost === void 0 ? {
1630
- usage: event.usage,
1631
- durationMs: event.durationMs
1632
- } : {
1633
- usage: event.usage,
1634
- durationMs: event.durationMs,
1635
- cost: event.cost
1636
- };
1637
- }
1638
- __name(doneToMetadata, "doneToMetadata");
2019
+ __name(presentUIMessageStream, "presentUIMessageStream");
1639
2020
 
1640
2021
  // src/bridge/agent-builder.ts
1641
2022
  function contextualTool(tool, _requiredContext) {
@@ -1701,6 +2082,14 @@ function makeBuilder(config) {
1701
2082
  ...config,
1702
2083
  settingSources: sources
1703
2084
  }), "settingSources"),
2085
+ memory: /* @__PURE__ */ __name((settings) => makeBuilder({
2086
+ ...config,
2087
+ memory: settings
2088
+ }), "memory"),
2089
+ hooks: /* @__PURE__ */ __name((map) => makeBuilder({
2090
+ ...config,
2091
+ hooks: map
2092
+ }), "hooks"),
1704
2093
  plugins: /* @__PURE__ */ __name((list) => makeBuilder({
1705
2094
  ...config,
1706
2095
  plugins: list
@@ -1862,6 +2251,7 @@ function streamAgentUIMessages(compiled, apiKey, input) {
1862
2251
  const overrides = {};
1863
2252
  if (input.cwd !== void 0) overrides.cwd = input.cwd;
1864
2253
  if (input.baseDir !== void 0) overrides.baseDir = input.baseDir;
2254
+ if (input.images !== void 0) overrides.images = input.images;
1865
2255
  let source;
1866
2256
  if (!input.hitl || input.hitl.gated.size === 0) {
1867
2257
  const events2 = createSdkAgentStream(compiled, compiled.tools, apiKey, overrides)(input.message, input.sessionId);
@@ -1902,7 +2292,7 @@ function streamAgentUIMessages(compiled, apiKey, input) {
1902
2292
  }
1903
2293
  const durableCheckpoint = compiled.checkpoint?.storage === "filesystem";
1904
2294
  const events = durableCheckpoint ? appendCheckpointSaved(source, input.sessionId) : source;
1905
- return translateToUIMessageStream(events, {
2295
+ return presentUIMessageStream(events, {
1906
2296
  textId
1907
2297
  });
1908
2298
  }
@@ -2223,10 +2613,10 @@ var DelegationError = class extends Error {
2223
2613
  };
2224
2614
 
2225
2615
  // src/loop/run-reflective-loop.ts
2226
- function asString2(value, fallback) {
2616
+ function asString3(value, fallback) {
2227
2617
  return typeof value === "string" ? value : fallback;
2228
2618
  }
2229
- __name(asString2, "asString");
2619
+ __name(asString3, "asString");
2230
2620
  function asNumber(value, fallback) {
2231
2621
  return typeof value === "number" ? value : fallback;
2232
2622
  }
@@ -2302,15 +2692,15 @@ function deriveFinishReason(signals) {
2302
2692
  }
2303
2693
  __name(deriveFinishReason, "deriveFinishReason");
2304
2694
  function pushToolResult(event, r, callInputs) {
2305
- const id = asString2(event.callId, "");
2695
+ const id = asString3(event.callId, "");
2306
2696
  const call = callInputs.get(id);
2307
2697
  r.toolCalls.push({
2308
2698
  id,
2309
- name: call?.name ?? asString2(event.toolName, "unknown"),
2699
+ name: call?.name ?? asString3(event.toolName, "unknown"),
2310
2700
  // Prefer the correlated tool_call input (real SDK shape); fall back to an input on the
2311
2701
  // result event itself (some streams/tests carry it there), else {}.
2312
2702
  input: call?.input ?? event.input ?? {},
2313
- output: asString2(event.output, "")
2703
+ output: asString3(event.output, "")
2314
2704
  });
2315
2705
  }
2316
2706
  __name(pushToolResult, "pushToolResult");
@@ -2329,8 +2719,8 @@ function accumulateEvent(event, r, signals, callInputs) {
2329
2719
  if (event.type === "text_delta" && typeof event.content === "string") {
2330
2720
  r.responseText += event.content;
2331
2721
  } else if (event.type === "tool_call") {
2332
- callInputs.set(asString2(event.callId, ""), {
2333
- name: asString2(event.toolName, "unknown"),
2722
+ callInputs.set(asString3(event.callId, ""), {
2723
+ name: asString3(event.toolName, "unknown"),
2334
2724
  input: event.input ?? {}
2335
2725
  });
2336
2726
  } else if (event.type === "tool_result") {
@@ -2338,11 +2728,11 @@ function accumulateEvent(event, r, signals, callInputs) {
2338
2728
  pushToolResult(event, r, callInputs);
2339
2729
  } else if (event.type === "done") {
2340
2730
  signals.sawDone = true;
2341
- signals.doneFinishReason = asString2(event.finishReason, "");
2731
+ signals.doneFinishReason = asString3(event.finishReason, "");
2342
2732
  applyDone(event, r);
2343
2733
  } else if (event.type === "error") {
2344
2734
  signals.sawError = true;
2345
- r.errorMessage = asString2(event.message, "Unknown agent error");
2735
+ r.errorMessage = asString3(event.message, "Unknown agent error");
2346
2736
  }
2347
2737
  }
2348
2738
  __name(accumulateEvent, "accumulateEvent");
@@ -3042,7 +3432,7 @@ export {
3042
3432
  extractThinkTagStream,
3043
3433
  createSdkAgentStream,
3044
3434
  toAgentFactory,
3045
- translateToUIMessageStream,
3435
+ presentUIMessageStream,
3046
3436
  contextualTool,
3047
3437
  agent,
3048
3438
  AgentDefinitionError,
@@ -3085,4 +3475,4 @@ export {
3085
3475
  generateAgentManifest,
3086
3476
  agentsPlugin
3087
3477
  };
3088
- //# sourceMappingURL=chunk-XRPFOFYF.js.map
3478
+ //# sourceMappingURL=chunk-YBNKD5UM.js.map