@noxsoft/anima 6.0.0 → 7.0.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.
Files changed (134) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.md +48 -0
  3. package/dist/{agent-VRQM14Xp.js → agent-BoAAHGEA.js} +3 -3
  4. package/dist/{agent-CnS0SRpT.js → agent-DuW0onwk.js} +4 -4
  5. package/dist/{agents-CvMRplDx.js → agents-BUXkSDns.js} +4 -4
  6. package/dist/{anthropic-direct-runner-C2Kwju-r.js → anthropic-direct-runner-DizCei79.js} +420 -4
  7. package/dist/{anthropic-direct-runner-BeYCnvZ8.js → anthropic-direct-runner-OjcTAH6g.js} +420 -3
  8. package/dist/{auth-choice-Dc5TAJwT.js → auth-choice-B1iGnjuE.js} +1 -1
  9. package/dist/{auth-choice-DY1saszS.js → auth-choice-HF9x6xk2.js} +1 -1
  10. package/dist/{banner-DAMtSjUF.js → banner-Dpa5d1If.js} +1 -1
  11. package/dist/build-info.json +3 -3
  12. package/dist/bundled/boot-md/handler.js +2 -2
  13. package/dist/bundled/session-memory/handler.js +1 -1
  14. package/dist/canvas-host/a2ui/.bundle.hash +1 -1
  15. package/dist/{channel-web-B8mzTSaY.js → channel-web-C5mzsaa3.js} +3 -3
  16. package/dist/{cli-hcHk5KuP.js → cli-Cuq4bIg4.js} +2 -2
  17. package/dist/{cli-D8exVpuI.js → cli-X9ikywQ3.js} +3 -3
  18. package/dist/{command-registry-D3VhxpWx.js → command-registry-9V4uqrBV.js} +12 -12
  19. package/dist/{completion-cli-B3BqQJq9.js → completion-cli-BtvcR-U5.js} +1 -1
  20. package/dist/{completion-cli-CepDzeW1.js → completion-cli-DNWDwhab.js} +2 -2
  21. package/dist/{config-cli-B6Np85rk.js → config-cli-DfHE3KG-.js} +1 -1
  22. package/dist/{config-cli-3CaIxSKo.js → config-cli-fleq7-gq.js} +1 -1
  23. package/dist/{configure-zXK6UZ51.js → configure-B2Mfnwy_.js} +3 -3
  24. package/dist/{configure-D88dg6mE.js → configure-SnvMHZPD.js} +7 -7
  25. package/dist/{configure-D882Bg7c.js → configure-ZWxixuRA.js} +3 -3
  26. package/dist/{configure-xpjwedvJ.js → configure-lkozxQed.js} +8 -8
  27. package/dist/context-mdxDsO1v.js +223 -0
  28. package/dist/control-ui/assets/index-Bwcvc7fq.css +1 -0
  29. package/dist/control-ui/assets/{index-yhFuaOnc.js → index-D4wqLVMN.js} +2 -2
  30. package/dist/control-ui/assets/{index-yhFuaOnc.js.map → index-D4wqLVMN.js.map} +1 -1
  31. package/dist/control-ui/assets/index-DIEQjjCN.js +73 -0
  32. package/dist/control-ui/assets/index-DIEQjjCN.js.map +1 -0
  33. package/dist/control-ui/assets/{observers-V7q9lNYt.js → observers-B7MfWiIZ.js} +2 -2
  34. package/dist/control-ui/assets/{observers-V7q9lNYt.js.map → observers-B7MfWiIZ.js.map} +1 -1
  35. package/dist/control-ui/index.html +2 -2
  36. package/dist/{deps-DyT32VfN.js → deps-BKLIBKjK.js} +1 -1
  37. package/dist/{doctor-WpKCNZeO.js → doctor-D7kKyUVk.js} +4 -4
  38. package/dist/{doctor-DEnSKgHu.js → doctor-DmCnZ-jF.js} +4 -4
  39. package/dist/{doctor-completion-CypXc1Uo.js → doctor-completion-B9SBdMoR.js} +1 -1
  40. package/dist/{doctor-completion-CPff9UlF.js → doctor-completion-BBvW4_J9.js} +1 -1
  41. package/dist/entry.js +1 -1
  42. package/dist/extensionAPI.js +1 -1
  43. package/dist/{gateway-cli-B_xsx5Nv.js → gateway-cli-CEM1vBuk.js} +15 -15
  44. package/dist/{gateway-cli-D3VBOA_i.js → gateway-cli-iumkTohn.js} +17 -17
  45. package/dist/{health-CabOEPQ0.js → health-B5N6_UOf.js} +3 -3
  46. package/dist/{health-C8KCBhuo.js → health-Cndq9b7A.js} +3 -3
  47. package/dist/{heartbeat-visibility-ZfNSbFcq.js → heartbeat-visibility-BQL13ZBH.js} +1 -1
  48. package/dist/{heartbeat-visibility-BjYY-mKG.js → heartbeat-visibility-CwcYugaR.js} +1 -1
  49. package/dist/{hooks-cli-Cs7GUa7G.js → hooks-cli-BZcvdIwE.js} +4 -4
  50. package/dist/{hooks-cli-DOs9WZ3K.js → hooks-cli-DSlPBQSY.js} +3 -3
  51. package/dist/index.js +10 -10
  52. package/dist/llm-slug-generator.js +1 -1
  53. package/dist/{login-BHnvW9HA.js → login-BEaBOSnw.js} +1 -1
  54. package/dist/{login-CrMpAZ0n.js → login-MzVPMRxL.js} +1 -1
  55. package/dist/{login-qr-DILcBA_q.js → login-qr-BjpDVBJE.js} +1 -1
  56. package/dist/{login-qr-CsAVGp00.js → login-qr-CxRI-tE2.js} +1 -1
  57. package/dist/{models-BM2_NkMu.js → models-CdNeYfSp.js} +4 -4
  58. package/dist/{models-cli-BpjeKsUz.js → models-cli-D7eSsPuk.js} +3 -3
  59. package/dist/{models-cli-BjY8wA-C.js → models-cli-fTZXo1zx.js} +5 -5
  60. package/dist/{onboard-DM9gULJN.js → onboard-C5K37NvY.js} +3 -3
  61. package/dist/{onboard-_-D81kAy.js → onboard-D-6QCnTi.js} +3 -3
  62. package/dist/{onboard-channels-UkphAdCy.js → onboard-channels-BsCq32Hn.js} +1 -1
  63. package/dist/{onboard-channels-CtT-RN60.js → onboard-channels-bx6oelzj.js} +1 -1
  64. package/dist/{onboarding-Djmm0PEM.js → onboarding-BeuMAyic.js} +4 -4
  65. package/dist/{onboarding-BB9PteK8.js → onboarding-CX1vIkcB.js} +4 -4
  66. package/dist/{outbound-send-deps-T_FgdfgW.js → outbound-send-deps-Y9AxHeLG.js} +1 -1
  67. package/dist/{pi-embedded-BMbtgOzv.js → pi-embedded-D15iww51.js} +1010 -104
  68. package/dist/{pi-embedded-DfbM3fAT.js → pi-embedded-DR8Pfd05.js} +1010 -104
  69. package/dist/{plugin-registry-QTkplP4s.js → plugin-registry-Do2D1nDk.js} +1 -1
  70. package/dist/{plugin-registry-DePMxn4z.js → plugin-registry-ME2FQAi-.js} +1 -1
  71. package/dist/plugin-sdk/affect/ego.d.ts +140 -0
  72. package/dist/plugin-sdk/agents/models-config.d.ts +5 -6
  73. package/dist/plugin-sdk/agents/noxsoft-runner.d.ts +3 -0
  74. package/dist/plugin-sdk/agents/openai-direct-runner.d.ts +41 -0
  75. package/dist/plugin-sdk/commands/steer.d.ts +49 -0
  76. package/dist/plugin-sdk/gateway/protocol/index.d.ts +2 -2
  77. package/dist/{plugins-cli-Dv0KQTWo.js → plugins-cli-CVFzwdmI.js} +4 -4
  78. package/dist/{plugins-cli-Bc9oU1ld.js → plugins-cli-CoVt2ewg.js} +3 -3
  79. package/dist/{program-CuwbF8YO.js → program-8rF4C_wd.js} +8 -8
  80. package/dist/{program-context-CxPfy-Wr.js → program-context-DP3qjW7A.js} +18 -18
  81. package/dist/{register.agent-DFQmkIEH.js → register.agent-BIrXCVtQ.js} +9 -9
  82. package/dist/{register.agent-DUjwGw9d.js → register.agent-DnkOx0U8.js} +7 -7
  83. package/dist/{register.anima-CtKNrpE8.js → register.anima-B36rTHUt.js} +2 -2
  84. package/dist/{register.anima-CRFHJu2J.js → register.anima-DXT9bM9A.js} +2 -2
  85. package/dist/{register.configure-CnEKV57N.js → register.configure-CuzJxZmk.js} +6 -6
  86. package/dist/{register.configure-CSSN07XN.js → register.configure-DCpvHX3m.js} +7 -7
  87. package/dist/{register.maintenance-fhcCB7ih.js → register.maintenance-CcxBFfv5.js} +10 -10
  88. package/dist/{register.maintenance-CU1A-90-.js → register.maintenance-Dla0H12S.js} +8 -8
  89. package/dist/{register.message-C1a0y2ZR.js → register.message-Brtushvp.js} +4 -4
  90. package/dist/{register.message-fM0jSKB8.js → register.message-CD7xV-jz.js} +5 -5
  91. package/dist/{register.onboard-BhPlqjFi.js → register.onboard-23Mra3LN.js} +11 -11
  92. package/dist/{register.onboard-B7Gavmvt.js → register.onboard-6CbODzQ6.js} +9 -9
  93. package/dist/{register.setup-CADdQUEN.js → register.setup-CqQw13Ky.js} +11 -11
  94. package/dist/{register.setup-0jPnMgnz.js → register.setup-DlVH7FKe.js} +9 -9
  95. package/dist/{register.status-health-sessions-Cu5fDT-z.js → register.status-health-sessions-CduFjFDB.js} +4 -4
  96. package/dist/{register.status-health-sessions-DdQsABr_.js → register.status-health-sessions-CxtgPKu9.js} +6 -6
  97. package/dist/{register.subclis-CZ91ufCy.js → register.subclis-CtANqD5P.js} +7 -7
  98. package/dist/{reply-DtHlnzOx.js → reply-93fMzde1.js} +610 -75
  99. package/dist/{reply-prefix-C8dIgJur.js → reply-prefix-B7Fb3fO8.js} +1 -1
  100. package/dist/{reply-prefix-DmWGtcH-.js → reply-prefix-BzdhJDqP.js} +1 -1
  101. package/dist/{run-Dfz_7j7t.js → run-CF3kHOGH.js} +1717 -83
  102. package/dist/{run-DqBQ-bGn.js → run-Cq_iTGK_.js} +1718 -84
  103. package/dist/{run-main-DGDW0fhx.js → run-main-BiIRcc6s.js} +17 -17
  104. package/dist/{server-node-events-Ca797E1d.js → server-node-events-B3Serk9L.js} +6 -6
  105. package/dist/{server-node-events-BR1aXVlu.js → server-node-events-DgvKcH5q.js} +5 -5
  106. package/dist/{session-C7IGnhd1.js → session-BMDpwIJu.js} +1 -1
  107. package/dist/{session-FmXsucR7.js → session-BzrnfWQ2.js} +2 -2
  108. package/dist/{session-DfsMJNG3.js → session-C_d9uvLf.js} +1 -1
  109. package/dist/{session-DLevr8Vd.js → session-jljC5QVG.js} +2 -2
  110. package/dist/{sessions-Dj7_4mkr.js → sessions-BmE5Z_1i.js} +1 -1
  111. package/dist/{settings-cli-DxNeu6kx.js → settings-cli-CZdlEmNi.js} +7 -7
  112. package/dist/{settings-cli-Dytfop1H.js → settings-cli-DsDqNpW_.js} +8 -8
  113. package/dist/{setup-token-B802CZwe.js → setup-token-C8Gg1P6T.js} +1 -1
  114. package/dist/{setup-token-DYh2QzJ-.js → setup-token-Lee4gM5w.js} +1 -1
  115. package/dist/{start-BqnPia0t.js → start-CK6urvnN.js} +17 -17
  116. package/dist/{start-C3fuLzX0.js → start-Cs1aPMq2.js} +15 -15
  117. package/dist/{status-CHGNPonc.js → status-BO5BIf81.js} +3 -3
  118. package/dist/{status-CxF6k_jr.js → status-COc4xMti.js} +1 -1
  119. package/dist/{status-tLgozFYL.js → status-C_NBOv_V.js} +1 -1
  120. package/dist/{status-DfZJJqNs.js → status-uakoP719.js} +4 -4
  121. package/dist/{subagent-registry-CPtElVX0.js → subagent-registry-fLI7QDKe.js} +449 -77
  122. package/dist/{update-cli-C-er5av6.js → update-cli-D3Ujz_cW.js} +10 -10
  123. package/dist/{update-cli-BuCw75tM.js → update-cli-DEe62XGU.js} +8 -8
  124. package/dist/{update-runner-kE8AMQt4.js → update-runner-DUl-g4mB.js} +1 -1
  125. package/dist/{update-runner-czCqHZCu.js → update-runner-DZfnquWO.js} +1 -1
  126. package/dist/{web-BHGK5GtV.js → web-C-cK9OCd.js} +1 -1
  127. package/dist/{web-DvTXV-fo.js → web-Di8j762D.js} +6 -6
  128. package/dist/{web-CyYunanU.js → web-Dybw4K7C.js} +6 -6
  129. package/dist/{web-so3pGceM.js → web-DzSlI8A6.js} +1 -1
  130. package/package.json +4 -4
  131. package/dist/context-B5X720Bs.js +0 -60
  132. package/dist/control-ui/assets/index-C4ejMN5U.js +0 -72
  133. package/dist/control-ui/assets/index-C4ejMN5U.js.map +0 -1
  134. package/dist/control-ui/assets/index-CcPNqN3R.css +0 -1
@@ -29,7 +29,7 @@ import { t as sanitizeToolResultImages } from "./tool-images-CgDT0Xzv.js";
29
29
  import { C as saveJsonFile, O as normalizeSecretInput, S as loadJsonFile, a as markAuthProfileUsed, i as markAuthProfileFailure, l as listProfilesForProvider, n as resolveAuthProfileOrder, p as ensureAuthProfileStore, r as isProfileInCooldown, s as resolveApiKeyForProfile, u as markAuthProfileGood, v as resolveAuthStorePathForDisplay, w as resolveAuthProfileDisplayLabel, y as resolveAnimaAgentDir } from "./auth-profiles-C-LuhW6c.js";
30
30
  import { i as resolveApiKeyForProvider, n as getCustomProviderApiKey, o as resolveEnvApiKey, r as requireApiKey, s as resolveModelAuthMode, t as getApiKeyForModel } from "./model-auth-CHB3EySM.js";
31
31
  import { n as SILENT_REPLY_TOKEN, r as isSilentReplyText, t as HEARTBEAT_TOKEN } from "./tokens-SP2Q7i59.js";
32
- import { $ as isVoiceCompatibleAudio, A as getLastTtsAttempt, B as resolveTtsConfig, C as formatUserTime, D as killProcessTree, E as getShellConfig, F as isTtsProviderConfigured, G as setTtsEnabled, I as maybeApplyTtsToPayload, J as textToSpeech, K as setTtsMaxLength, L as normalizeTtsAutoMode, M as getTtsProvider, N as isSummarizationEnabled, O as sanitizeBinaryOutput, P as isTtsEnabled, R as resolveTtsApiKey, S as buildSystemPromptParams, T as resolveUserTimezone, U as setLastTtsAttempt, V as resolveTtsPrefsPath, W as setSummarizationEnabled, Y as textToSpeechTelephony, _ as resolvePromptInput, at as triggerInternalHook, b as writeCliImages, c as appendImagePathsToPrompt, d as cleanupResumeProcesses, et as makeBootstrapWarn, f as cleanupSuspendedCliProcesses, g as parseCliJsonl, h as parseCliJson, i as resolveRunWorkspaceDir, it as registerInternalHook, j as getTtsMaxLength, k as buildTtsSystemPromptHint, l as buildCliArgs, lt as resolveHeartbeatPrompt, m as normalizeCliModel, o as appendRunnerCapabilityPrompt, p as enqueueCliRun, q as setTtsProvider, r as redactRunIdentifier, rt as createInternalHookEvent, s as resolveAnimaDocsPath, t as runAnthropicDirectAgent, tt as resolveBootstrapContextForRun, u as buildSystemPrompt, ut as stripHeartbeatToken, v as resolveSessionIdToSend, w as resolveUserTimeFormat, x as buildAgentSystemPrompt, y as resolveSystemPromptUsage, z as resolveTtsAutoMode } from "./anthropic-direct-runner-BeYCnvZ8.js";
32
+ import { $ as isVoiceCompatibleAudio, A as getLastTtsAttempt, B as resolveTtsConfig, C as formatUserTime, D as killProcessTree, E as getShellConfig, F as isTtsProviderConfigured, G as setTtsEnabled, I as maybeApplyTtsToPayload, J as textToSpeech, K as setTtsMaxLength, L as normalizeTtsAutoMode, M as getTtsProvider, N as isSummarizationEnabled, O as sanitizeBinaryOutput, P as isTtsEnabled, R as resolveTtsApiKey, S as buildSystemPromptParams, T as resolveUserTimezone, U as setLastTtsAttempt, V as resolveTtsPrefsPath, W as setSummarizationEnabled, Y as textToSpeechTelephony, _ as resolvePromptInput, at as makeBootstrapWarn, b as writeCliImages, c as appendImagePathsToPrompt, ct as createInternalHookEvent, d as cleanupResumeProcesses, f as cleanupSuspendedCliProcesses, g as parseCliJsonl, h as parseCliJson, ht as stripHeartbeatToken, i as resolveRunWorkspaceDir, j as getTtsMaxLength, k as buildTtsSystemPromptHint, l as buildCliArgs, lt as registerInternalHook, m as normalizeCliModel, mt as resolveHeartbeatPrompt, o as appendRunnerCapabilityPrompt, ot as resolveBootstrapContextForRun, p as enqueueCliRun, q as setTtsProvider, r as redactRunIdentifier, s as resolveAnimaDocsPath, t as runAnthropicDirectAgent, u as buildSystemPrompt, ut as triggerInternalHook, v as resolveSessionIdToSend, w as resolveUserTimeFormat, x as buildAgentSystemPrompt, y as resolveSystemPromptUsage, z as resolveTtsAutoMode } from "./anthropic-direct-runner-OjcTAH6g.js";
33
33
  import { _ as throwIfAborted, b as initializeGlobalHookRunner, c as applyReplyThreading, d as shouldSuppressMessagingToolReplies, f as createReplyToModeFilterForChannel, g as normalizeTargetForProvider, h as normalizeChannelTargetInput, l as filterMessagingToolDuplicates, m as buildTargetResolverSignature, o as normalizeReplyPayloadsForDelivery, p as resolveReplyToMode, s as applyReplyTagsToPayload, t as deliverOutboundPayloads, u as isRenderablePayload, v as parseReplyDirectives, y as getGlobalHookRunner } from "./deliver-BKzX3YoN.js";
34
34
  import { i as resolveMemoryBackendConfig, n as registerMemoryCli, r as getMemorySearchManager } from "./memory-cli-DLtBA6r5.js";
35
35
  import { n as resolveMemorySearchConfig } from "./manager-D8VCuzru.js";
@@ -1692,22 +1692,185 @@ function formatAudioTranscripts(outputs) {
1692
1692
  //#endregion
1693
1693
  //#region src/agents/models-config.ts
1694
1694
  /**
1695
- * Models configuration — SIMPLIFIED
1695
+ * Models configuration — Multi-provider
1696
1696
  *
1697
- * The multi-provider LLM abstraction (pi-ai) has been removed.
1698
- * ANIMA uses Claude Code CLI exclusively. This file retains only
1699
- * the minimal interface needed by the rest of the codebase.
1700
- * Full replacement comes in Phase 2.
1697
+ * ANIMA 6.5+ supports direct API runners for Anthropic, Google, OpenAI,
1698
+ * and AWS Bedrock. This file seeds the models.json with all known models
1699
+ * so the PI SDK ModelRegistry can discover them for the model catalog.
1701
1700
  */
1701
+ /** Seed catalog — all models ANIMA can route to via direct runners. */
1702
+ const SEED_MODELS = [
1703
+ {
1704
+ id: "gpt-5.4",
1705
+ name: "GPT-5.4",
1706
+ provider: "openai",
1707
+ contextWindow: 1048576,
1708
+ reasoning: true,
1709
+ input: ["text", "image"]
1710
+ },
1711
+ {
1712
+ id: "gpt-5.2",
1713
+ name: "GPT-5.2",
1714
+ provider: "openai",
1715
+ contextWindow: 256e3,
1716
+ reasoning: true,
1717
+ input: ["text", "image"]
1718
+ },
1719
+ {
1720
+ id: "gpt-4.1",
1721
+ name: "GPT-4.1",
1722
+ provider: "openai",
1723
+ contextWindow: 1048576,
1724
+ reasoning: false,
1725
+ input: ["text", "image"]
1726
+ },
1727
+ {
1728
+ id: "gpt-4.1-mini",
1729
+ name: "GPT-4.1 Mini",
1730
+ provider: "openai",
1731
+ contextWindow: 1048576,
1732
+ reasoning: false,
1733
+ input: ["text", "image"]
1734
+ },
1735
+ {
1736
+ id: "gpt-4.1-nano",
1737
+ name: "GPT-4.1 Nano",
1738
+ provider: "openai",
1739
+ contextWindow: 1048576,
1740
+ reasoning: false,
1741
+ input: ["text"]
1742
+ },
1743
+ {
1744
+ id: "gpt-4o",
1745
+ name: "GPT-4o",
1746
+ provider: "openai",
1747
+ contextWindow: 128e3,
1748
+ reasoning: false,
1749
+ input: ["text", "image"]
1750
+ },
1751
+ {
1752
+ id: "gpt-4o-mini",
1753
+ name: "GPT-4o Mini",
1754
+ provider: "openai",
1755
+ contextWindow: 128e3,
1756
+ reasoning: false,
1757
+ input: ["text", "image"]
1758
+ },
1759
+ {
1760
+ id: "o3",
1761
+ name: "o3",
1762
+ provider: "openai",
1763
+ contextWindow: 2e5,
1764
+ reasoning: true,
1765
+ input: ["text", "image"]
1766
+ },
1767
+ {
1768
+ id: "o3-mini",
1769
+ name: "o3-mini",
1770
+ provider: "openai",
1771
+ contextWindow: 2e5,
1772
+ reasoning: true,
1773
+ input: ["text"]
1774
+ },
1775
+ {
1776
+ id: "o4-mini",
1777
+ name: "o4-mini",
1778
+ provider: "openai",
1779
+ contextWindow: 2e5,
1780
+ reasoning: true,
1781
+ input: ["text", "image"]
1782
+ },
1783
+ {
1784
+ id: "gemini-2.5-flash",
1785
+ name: "Gemini 2.5 Flash",
1786
+ provider: "google",
1787
+ contextWindow: 1048576,
1788
+ reasoning: true,
1789
+ input: ["text", "image"]
1790
+ },
1791
+ {
1792
+ id: "gemini-2.5-pro",
1793
+ name: "Gemini 2.5 Pro",
1794
+ provider: "google",
1795
+ contextWindow: 1048576,
1796
+ reasoning: true,
1797
+ input: ["text", "image"]
1798
+ },
1799
+ {
1800
+ id: "gemini-2.0-flash",
1801
+ name: "Gemini 2.0 Flash",
1802
+ provider: "google",
1803
+ contextWindow: 1048576,
1804
+ reasoning: false,
1805
+ input: ["text", "image"]
1806
+ },
1807
+ {
1808
+ id: "claude-opus-4-6",
1809
+ name: "Claude Opus 4.6",
1810
+ provider: "anthropic",
1811
+ contextWindow: 1e6,
1812
+ reasoning: true,
1813
+ input: ["text", "image"]
1814
+ },
1815
+ {
1816
+ id: "claude-sonnet-4-6",
1817
+ name: "Claude Sonnet 4.6",
1818
+ provider: "anthropic",
1819
+ contextWindow: 1e6,
1820
+ reasoning: true,
1821
+ input: ["text", "image"]
1822
+ },
1823
+ {
1824
+ id: "claude-haiku-4-5",
1825
+ name: "Claude Haiku 4.5",
1826
+ provider: "anthropic",
1827
+ contextWindow: 2e5,
1828
+ reasoning: false,
1829
+ input: ["text", "image"]
1830
+ },
1831
+ {
1832
+ id: "amazon.nova-micro-v1:0",
1833
+ name: "Amazon Nova Micro",
1834
+ provider: "amazon-bedrock",
1835
+ contextWindow: 128e3,
1836
+ reasoning: false,
1837
+ input: ["text"]
1838
+ },
1839
+ {
1840
+ id: "amazon.nova-lite-v1:0",
1841
+ name: "Amazon Nova Lite",
1842
+ provider: "amazon-bedrock",
1843
+ contextWindow: 3e5,
1844
+ reasoning: false,
1845
+ input: ["text", "image"]
1846
+ }
1847
+ ];
1702
1848
  async function ensureAnimaModelsJson(config, agentDirOverride) {
1703
- config ?? loadConfig();
1704
1849
  const agentDir = agentDirOverride?.trim() ? agentDirOverride.trim() : resolveAnimaAgentDir();
1705
1850
  await fs$1.mkdir(agentDir, {
1706
1851
  recursive: true,
1707
1852
  mode: 448
1708
1853
  });
1709
1854
  const targetPath = path.join(agentDir, "models.json");
1710
- const content = JSON.stringify({ providers: {} }, null, 2) + "\n";
1855
+ let existingData = {};
1856
+ try {
1857
+ const raw = await fs$1.readFile(targetPath, "utf8");
1858
+ existingData = JSON.parse(raw);
1859
+ } catch {}
1860
+ const existingModels = Array.isArray(existingData.models) ? existingData.models : [];
1861
+ const existingIds = new Set(existingModels.filter((m) => typeof m?.id === "string").map((m) => `${m.provider}/${m.id}`));
1862
+ const merged = [...existingModels];
1863
+ for (const seed of SEED_MODELS) {
1864
+ const key = `${seed.provider}/${seed.id}`;
1865
+ if (!existingIds.has(key)) {
1866
+ merged.push(seed);
1867
+ existingIds.add(key);
1868
+ }
1869
+ }
1870
+ const content = JSON.stringify({
1871
+ providers: existingData.providers ?? {},
1872
+ models: merged
1873
+ }, null, 2) + "\n";
1711
1874
  let existing = "";
1712
1875
  try {
1713
1876
  existing = await fs$1.readFile(targetPath, "utf8");
@@ -4903,7 +5066,7 @@ function resolveCliBackendConfig(provider, cfg, options) {
4903
5066
 
4904
5067
  //#endregion
4905
5068
  //#region src/agents/cli-runner.ts
4906
- const log$6 = createSubsystemLogger("agent/claude-cli");
5069
+ const log$7 = createSubsystemLogger("agent/claude-cli");
4907
5070
  async function runCliAgent(params) {
4908
5071
  const started = Date.now();
4909
5072
  const workspaceResolution = resolveRunWorkspaceDir({
@@ -4916,7 +5079,7 @@ async function runCliAgent(params) {
4916
5079
  const redactedSessionId = redactRunIdentifier(params.sessionId);
4917
5080
  const redactedSessionKey = redactRunIdentifier(params.sessionKey);
4918
5081
  const redactedWorkspace = redactRunIdentifier(resolvedWorkspace);
4919
- if (workspaceResolution.usedFallback) log$6.warn(`[workspace-fallback] caller=runCliAgent reason=${workspaceResolution.fallbackReason} run=${params.runId} session=${redactedSessionId} sessionKey=${redactedSessionKey} agent=${workspaceResolution.agentId} workspace=${redactedWorkspace}`);
5082
+ if (workspaceResolution.usedFallback) log$7.warn(`[workspace-fallback] caller=runCliAgent reason=${workspaceResolution.fallbackReason} run=${params.runId} session=${redactedSessionId} sessionKey=${redactedSessionKey} agent=${workspaceResolution.agentId} workspace=${redactedWorkspace}`);
4920
5083
  const workspaceDir = resolvedWorkspace;
4921
5084
  const backendResolved = resolveCliBackendConfig(params.provider, params.config, { execSecurity: params.sessionExecSecurity });
4922
5085
  if (!backendResolved) throw new Error(`Unknown CLI backend: ${params.provider}`);
@@ -4934,7 +5097,7 @@ async function runCliAgent(params) {
4934
5097
  sessionId: params.sessionId,
4935
5098
  warn: makeBootstrapWarn({
4936
5099
  sessionLabel,
4937
- warn: (message) => log$6.warn(message)
5100
+ warn: (message) => log$7.warn(message)
4938
5101
  })
4939
5102
  });
4940
5103
  const { defaultAgentId, sessionAgentId } = resolveSessionAgentIds({
@@ -4976,17 +5139,17 @@ async function runCliAgent(params) {
4976
5139
  const previousMode = parsed.metadata?.effectiveCodexExecMode ?? parsed.metadata?.effectiveSandbox;
4977
5140
  const currentMode = effectiveCodexExecMode;
4978
5141
  if (!previousMode) {
4979
- log$6.info("Codex execution mode is unknown for the saved session; forcing session restart.");
5142
+ log$7.info("Codex execution mode is unknown for the saved session; forcing session restart.");
4980
5143
  useResume = false;
4981
5144
  isNew = true;
4982
5145
  } else if (previousMode !== currentMode) {
4983
- log$6.info(`Codex execution mode changed (${previousMode} -> ${currentMode}); forcing session restart.`);
5146
+ log$7.info(`Codex execution mode changed (${previousMode} -> ${currentMode}); forcing session restart.`);
4984
5147
  useResume = false;
4985
5148
  isNew = true;
4986
5149
  }
4987
5150
  }
4988
5151
  } catch {
4989
- log$6.info("Codex session transcript is unavailable; forcing session restart.");
5152
+ log$7.info("Codex session transcript is unavailable; forcing session restart.");
4990
5153
  useResume = false;
4991
5154
  isNew = true;
4992
5155
  }
@@ -5031,7 +5194,7 @@ async function runCliAgent(params) {
5031
5194
  const queueKey = backend.serialize ?? true ? backendResolved.id : `${backendResolved.id}:${params.runId}`;
5032
5195
  try {
5033
5196
  const output = await enqueueCliRun(queueKey, async () => {
5034
- log$6.info(`cli exec: provider=${params.provider} model=${normalizedModel} promptChars=${params.prompt.length}`);
5197
+ log$7.info(`cli exec: provider=${params.provider} model=${normalizedModel} promptChars=${params.prompt.length}`);
5035
5198
  const logOutputText = isTruthyEnvValue(process.env.ANIMA_CLAUDE_CLI_LOG_OUTPUT);
5036
5199
  if (logOutputText) {
5037
5200
  const logArgs = [];
@@ -5064,7 +5227,7 @@ async function runCliAgent(params) {
5064
5227
  const promptIndex = logArgs.indexOf(argsPrompt);
5065
5228
  if (promptIndex >= 0) logArgs[promptIndex] = `<prompt:${argsPrompt.length} chars>`;
5066
5229
  }
5067
- log$6.info(`cli argv: ${backend.command} ${logArgs.join(" ")}`);
5230
+ log$7.info(`cli argv: ${backend.command} ${logArgs.join(" ")}`);
5068
5231
  }
5069
5232
  const env = (() => {
5070
5233
  const next = {
@@ -5097,12 +5260,12 @@ async function runCliAgent(params) {
5097
5260
  const stdout = result.stdout.trim();
5098
5261
  const stderr = result.stderr.trim();
5099
5262
  if (logOutputText) {
5100
- if (stdout) log$6.info(`cli stdout:\n${stdout}`);
5101
- if (stderr) log$6.info(`cli stderr:\n${stderr}`);
5263
+ if (stdout) log$7.info(`cli stdout:\n${stdout}`);
5264
+ if (stderr) log$7.info(`cli stderr:\n${stderr}`);
5102
5265
  }
5103
5266
  if (shouldLogVerbose()) {
5104
- if (stdout) log$6.debug(`cli stdout:\n${stdout}`);
5105
- if (stderr) log$6.debug(`cli stderr:\n${stderr}`);
5267
+ if (stdout) log$7.debug(`cli stdout:\n${stdout}`);
5268
+ if (stderr) log$7.debug(`cli stderr:\n${stderr}`);
5106
5269
  }
5107
5270
  if (result.code !== 0) {
5108
5271
  const timedOut = result.killed && result.signal === "SIGKILL";
@@ -9025,7 +9188,7 @@ function createWhatsAppLoginTool() {
9025
9188
  force: Type.Optional(Type.Boolean())
9026
9189
  }),
9027
9190
  execute: async (_toolCallId, args) => {
9028
- const { startWebLoginWithQr, waitForWebLogin } = await import("./login-qr-CsAVGp00.js");
9191
+ const { startWebLoginWithQr, waitForWebLogin } = await import("./login-qr-CxRI-tE2.js");
9029
9192
  if ((args?.action ?? "start") === "wait") {
9030
9193
  const result = await waitForWebLogin({ timeoutMs: typeof args.timeoutMs === "number" ? args.timeoutMs : void 0 });
9031
9194
  return {
@@ -9475,15 +9638,15 @@ function loadWebOutbound() {
9475
9638
  return webOutboundPromise;
9476
9639
  }
9477
9640
  function loadWebLogin() {
9478
- webLoginPromise ??= import("./login-BHnvW9HA.js").then((n) => n.n);
9641
+ webLoginPromise ??= import("./login-BEaBOSnw.js").then((n) => n.n);
9479
9642
  return webLoginPromise;
9480
9643
  }
9481
9644
  function loadWebLoginQr() {
9482
- webLoginQrPromise ??= import("./login-qr-CsAVGp00.js");
9645
+ webLoginQrPromise ??= import("./login-qr-CxRI-tE2.js");
9483
9646
  return webLoginQrPromise;
9484
9647
  }
9485
9648
  function loadWebChannel() {
9486
- webChannelPromise ??= import("./web-CyYunanU.js");
9649
+ webChannelPromise ??= import("./web-Dybw4K7C.js");
9487
9650
  return webChannelPromise;
9488
9651
  }
9489
9652
  function loadWhatsAppActions() {
@@ -9963,7 +10126,7 @@ function loadAnimaPlugins(options = {}) {
9963
10126
 
9964
10127
  //#endregion
9965
10128
  //#region src/plugins/tools.ts
9966
- const log$5 = createSubsystemLogger("plugins");
10129
+ const log$6 = createSubsystemLogger("plugins");
9967
10130
  const pluginToolMeta = /* @__PURE__ */ new WeakMap();
9968
10131
  function getPluginToolMeta(tool) {
9969
10132
  return pluginToolMeta.get(tool);
@@ -9986,10 +10149,10 @@ function resolvePluginTools(params) {
9986
10149
  config: effectiveConfig,
9987
10150
  workspaceDir: params.context.workspaceDir,
9988
10151
  logger: {
9989
- info: (msg) => log$5.info(msg),
9990
- warn: (msg) => log$5.warn(msg),
9991
- error: (msg) => log$5.error(msg),
9992
- debug: (msg) => log$5.debug(msg)
10152
+ info: (msg) => log$6.info(msg),
10153
+ warn: (msg) => log$6.warn(msg),
10154
+ error: (msg) => log$6.error(msg),
10155
+ debug: (msg) => log$6.debug(msg)
9993
10156
  }
9994
10157
  });
9995
10158
  const tools = [];
@@ -10002,7 +10165,7 @@ function resolvePluginTools(params) {
10002
10165
  const pluginIdKey = normalizeToolName(entry.pluginId);
10003
10166
  if (existingNormalized.has(pluginIdKey)) {
10004
10167
  const message = `plugin id conflicts with core tool name (${entry.pluginId})`;
10005
- log$5.error(message);
10168
+ log$6.error(message);
10006
10169
  registry.diagnostics.push({
10007
10170
  level: "error",
10008
10171
  pluginId: entry.pluginId,
@@ -10016,7 +10179,7 @@ function resolvePluginTools(params) {
10016
10179
  try {
10017
10180
  resolved = entry.factory(params.context);
10018
10181
  } catch (err) {
10019
- log$5.error(`plugin tool failed (${entry.pluginId}): ${String(err)}`);
10182
+ log$6.error(`plugin tool failed (${entry.pluginId}): ${String(err)}`);
10020
10183
  continue;
10021
10184
  }
10022
10185
  if (!resolved) continue;
@@ -10031,7 +10194,7 @@ function resolvePluginTools(params) {
10031
10194
  for (const tool of list) {
10032
10195
  if (nameSet.has(tool.name) || existing.has(tool.name)) {
10033
10196
  const message = `plugin tool name conflict (${entry.pluginId}): ${tool.name}`;
10034
- log$5.error(message);
10197
+ log$6.error(message);
10035
10198
  registry.diagnostics.push({
10036
10199
  level: "error",
10037
10200
  pluginId: entry.pluginId,
@@ -20421,7 +20584,7 @@ async function resolveAnnounceTarget(params) {
20421
20584
 
20422
20585
  //#endregion
20423
20586
  //#region src/agents/tools/sessions-send-tool.a2a.ts
20424
- const log$4 = createSubsystemLogger("agents/sessions-send");
20587
+ const log$5 = createSubsystemLogger("agents/sessions-send");
20425
20588
  async function runSessionsSendA2AFlow(params) {
20426
20589
  const runContextId = params.waitRunId ?? "unknown";
20427
20590
  try {
@@ -20512,7 +20675,7 @@ async function runSessionsSendA2AFlow(params) {
20512
20675
  timeoutMs: 1e4
20513
20676
  });
20514
20677
  } catch (err) {
20515
- log$4.warn("sessions_send announce delivery failed", {
20678
+ log$5.warn("sessions_send announce delivery failed", {
20516
20679
  runId: runContextId,
20517
20680
  channel: announceTarget.channel,
20518
20681
  to: announceTarget.to,
@@ -20520,7 +20683,7 @@ async function runSessionsSendA2AFlow(params) {
20520
20683
  });
20521
20684
  }
20522
20685
  } catch (err) {
20523
- log$4.warn("sessions_send announce flow failed", {
20686
+ log$5.warn("sessions_send announce flow failed", {
20524
20687
  runId: runContextId,
20525
20688
  error: formatErrorMessage(err)
20526
20689
  });
@@ -25890,7 +26053,7 @@ function wrapToolWithAbortSignal(tool, abortSignal) {
25890
26053
 
25891
26054
  //#endregion
25892
26055
  //#region src/agents/pi-tools.before-tool-call.ts
25893
- const log$3 = createSubsystemLogger("agents/tools");
26056
+ const log$4 = createSubsystemLogger("agents/tools");
25894
26057
  const BEFORE_TOOL_CALL_WRAPPED = Symbol("beforeToolCallWrapped");
25895
26058
  const adjustedParamsByToolCallId = /* @__PURE__ */ new Map();
25896
26059
  const MAX_TRACKED_ADJUSTED_PARAMS = 1024;
@@ -25931,7 +26094,7 @@ async function runBeforeToolCallHook(args) {
25931
26094
  }
25932
26095
  } catch (err) {
25933
26096
  const toolCallId = args.toolCallId ? ` toolCallId=${args.toolCallId}` : "";
25934
- log$3.warn(`before_tool_call hook failed: tool=${toolName}${toolCallId} error=${String(err)}`);
26097
+ log$4.warn(`before_tool_call hook failed: tool=${toolName}${toolCallId} error=${String(err)}`);
25935
26098
  }
25936
26099
  return {
25937
26100
  blocked: false,
@@ -26893,9 +27056,9 @@ function createAnimaCodingTools(options) {
26893
27056
 
26894
27057
  //#endregion
26895
27058
  //#region src/agents/gemini-direct-runner.ts
26896
- const log$2 = createSubsystemLogger("agent/gemini-direct");
27059
+ const log$3 = createSubsystemLogger("agent/gemini-direct");
26897
27060
  const DEFAULT_GEMINI_BASE_URL = "https://generativelanguage.googleapis.com/v1beta";
26898
- const MODEL_MAP = {
27061
+ const MODEL_MAP$1 = {
26899
27062
  gemini: "gemini-2.5-flash",
26900
27063
  "gemini-pro": "gemini-2.5-pro",
26901
27064
  "gemini-flash": "gemini-2.5-flash",
@@ -26908,9 +27071,9 @@ const MODEL_MAP = {
26908
27071
  "gemini-3.1-pro-preview": "gemini-3.1-pro-preview",
26909
27072
  default: "gemini-2.5-flash"
26910
27073
  };
26911
- const HISTORY_FILE_SUFFIX = ".gemini-history.json";
26912
- async function loadSessionHistory(sessionFile) {
26913
- const histPath = sessionFile + HISTORY_FILE_SUFFIX;
27074
+ const HISTORY_FILE_SUFFIX$1 = ".gemini-history.json";
27075
+ async function loadSessionHistory$1(sessionFile) {
27076
+ const histPath = sessionFile + HISTORY_FILE_SUFFIX$1;
26914
27077
  try {
26915
27078
  const raw = await fs$1.readFile(histPath, "utf8");
26916
27079
  return JSON.parse(raw);
@@ -26918,18 +27081,18 @@ async function loadSessionHistory(sessionFile) {
26918
27081
  return null;
26919
27082
  }
26920
27083
  }
26921
- async function saveSessionHistory(sessionFile, history) {
26922
- const histPath = sessionFile + HISTORY_FILE_SUFFIX;
27084
+ async function saveSessionHistory$1(sessionFile, history) {
27085
+ const histPath = sessionFile + HISTORY_FILE_SUFFIX$1;
26923
27086
  try {
26924
27087
  await fs$1.mkdir(path.dirname(histPath), { recursive: true });
26925
27088
  await fs$1.writeFile(histPath, JSON.stringify(history, null, 2), "utf8");
26926
27089
  } catch (err) {
26927
- log$2.warn("failed to save session history", { error: String(err) });
27090
+ log$3.warn("failed to save session history", { error: String(err) });
26928
27091
  }
26929
27092
  }
26930
- function resolveModel(model) {
27093
+ function resolveModel$1(model) {
26931
27094
  const key = (model ?? "default").trim().toLowerCase() || "default";
26932
- return MODEL_MAP[key] ?? key;
27095
+ return MODEL_MAP$1[key] ?? key;
26933
27096
  }
26934
27097
  function buildModelPath(model) {
26935
27098
  return model.startsWith("models/") ? model : `models/${model}`;
@@ -26942,9 +27105,9 @@ function buildModelPath(model) {
26942
27105
  */
26943
27106
  async function runGeminiDirectAgent(params) {
26944
27107
  const started = Date.now();
26945
- const resolvedModel = resolveModel(params.model);
27108
+ const resolvedModel = resolveModel$1(params.model);
26946
27109
  const modelPath = buildModelPath(resolvedModel);
26947
- log$2.info(`direct api exec: model=${resolvedModel} promptChars=${params.prompt.length}`);
27110
+ log$3.info(`direct api exec: model=${resolvedModel} promptChars=${params.prompt.length}`);
26948
27111
  const workspaceDir = resolveRunWorkspaceDir({
26949
27112
  workspaceDir: params.workspaceDir,
26950
27113
  sessionKey: params.sessionKey,
@@ -26970,7 +27133,7 @@ async function runGeminiDirectAgent(params) {
26970
27133
  sessionId: params.sessionId,
26971
27134
  warn: makeBootstrapWarn({
26972
27135
  sessionLabel: params.sessionKey ?? params.sessionId,
26973
- warn: (msg) => log$2.warn(msg)
27136
+ warn: (msg) => log$3.warn(msg)
26974
27137
  })
26975
27138
  });
26976
27139
  const { defaultAgentId, sessionAgentId } = resolveSessionAgentIds({
@@ -26998,7 +27161,7 @@ async function runGeminiDirectAgent(params) {
26998
27161
  modelDisplay: `google/${resolvedModel}`,
26999
27162
  agentId: sessionAgentId
27000
27163
  });
27001
- let history = await loadSessionHistory(params.sessionFile);
27164
+ let history = await loadSessionHistory$1(params.sessionFile);
27002
27165
  if (!history) history = {
27003
27166
  sessionId: params.sessionId,
27004
27167
  contents: [],
@@ -27034,7 +27197,7 @@ async function runGeminiDirectAgent(params) {
27034
27197
  method: "POST",
27035
27198
  headers: {
27036
27199
  "Content-Type": "application/json",
27037
- "User-Agent": `anima/5.0.1 (gemini-direct-runner; ${os.platform()})`
27200
+ "User-Agent": `anima/7.0.0 (gemini-direct-runner; ${os.platform()})`
27038
27201
  },
27039
27202
  body: JSON.stringify(requestBody),
27040
27203
  signal: controller.signal
@@ -27047,7 +27210,7 @@ async function runGeminiDirectAgent(params) {
27047
27210
  const rateHint = isRateLimit ? " — rate limit hit, will retry next heartbeat." : "";
27048
27211
  const authHint = isAuth ? " — API key may be invalid. Check GEMINI_API_KEY environment variable." : "";
27049
27212
  console.error("GEMINI API ERROR BODY:", body);
27050
- log$2.error(`gemini api error: HTTP ${response.status}${authHint}${rateHint}`, {
27213
+ log$3.error(`gemini api error: HTTP ${response.status}${authHint}${rateHint}`, {
27051
27214
  status: response.status,
27052
27215
  body: body.slice(0, 500)
27053
27216
  });
@@ -27150,7 +27313,7 @@ async function runGeminiDirectAgent(params) {
27150
27313
  const isAbort = err instanceof Error && err.name === "AbortError";
27151
27314
  const errorKind = isAbort ? "timeout" : "unknown";
27152
27315
  const errorMsg = isAbort ? `Request timed out after ${params.timeoutMs}ms` : String(err);
27153
- log$2.error(`gemini api error: ${errorMsg}`, { error: String(err) });
27316
+ log$3.error(`gemini api error: ${errorMsg}`, { error: String(err) });
27154
27317
  return {
27155
27318
  status: isAbort ? "timeout" : "failed",
27156
27319
  meta: {
@@ -27164,9 +27327,9 @@ async function runGeminiDirectAgent(params) {
27164
27327
  }
27165
27328
  }
27166
27329
  history.updatedAt = Date.now();
27167
- await saveSessionHistory(params.sessionFile, history);
27330
+ await saveSessionHistory$1(params.sessionFile, history);
27168
27331
  const durationMs = Date.now() - started;
27169
- log$2.info(`gemini api complete: ${durationMs}ms`, {
27332
+ log$3.info(`gemini api complete: ${durationMs}ms`, {
27170
27333
  inputTokens: totalInputTokens,
27171
27334
  outputTokens: totalOutputTokens
27172
27335
  });
@@ -27188,6 +27351,338 @@ async function runGeminiDirectAgent(params) {
27188
27351
  };
27189
27352
  }
27190
27353
 
27354
+ //#endregion
27355
+ //#region src/agents/openai-direct-runner.ts
27356
+ const log$2 = createSubsystemLogger("agent/openai-direct");
27357
+ const DEFAULT_OPENAI_BASE_URL = "https://api.openai.com/v1";
27358
+ const MODEL_MAP = {
27359
+ "gpt-5.4": "gpt-5.4",
27360
+ "gpt-5.2": "gpt-5.2",
27361
+ "gpt-5": "gpt-5.4",
27362
+ "gpt-4.1": "gpt-4.1",
27363
+ "gpt-4.1-mini": "gpt-4.1-mini",
27364
+ "gpt-4.1-nano": "gpt-4.1-nano",
27365
+ "gpt-4o": "gpt-4o",
27366
+ "gpt-4o-mini": "gpt-4o-mini",
27367
+ o3: "o3",
27368
+ "o3-mini": "o3-mini",
27369
+ "o4-mini": "o4-mini",
27370
+ default: "gpt-4.1"
27371
+ };
27372
+ const HISTORY_FILE_SUFFIX = ".openai-history.json";
27373
+ async function loadSessionHistory(sessionFile) {
27374
+ const histPath = sessionFile + HISTORY_FILE_SUFFIX;
27375
+ try {
27376
+ const raw = await fs$1.readFile(histPath, "utf8");
27377
+ return JSON.parse(raw);
27378
+ } catch {
27379
+ return null;
27380
+ }
27381
+ }
27382
+ async function saveSessionHistory(sessionFile, history) {
27383
+ const histPath = sessionFile + HISTORY_FILE_SUFFIX;
27384
+ try {
27385
+ await fs$1.mkdir(path.dirname(histPath), { recursive: true });
27386
+ await fs$1.writeFile(histPath, JSON.stringify(history, null, 2), "utf8");
27387
+ } catch (err) {
27388
+ log$2.warn("failed to save session history", { error: String(err) });
27389
+ }
27390
+ }
27391
+ function resolveModel(model) {
27392
+ const key = (model ?? "default").trim().toLowerCase() || "default";
27393
+ return MODEL_MAP[key] ?? key;
27394
+ }
27395
+ /**
27396
+ * Clean a JSON Schema for OpenAI's function calling.
27397
+ * OpenAI is stricter than most — no unsupported keywords.
27398
+ */
27399
+ function cleanSchemaForOpenAI(schema) {
27400
+ const cleaned = {};
27401
+ for (const [key, value] of Object.entries(schema)) {
27402
+ if (key === "$schema" || key === "additionalProperties" || key === "$id") continue;
27403
+ if (key === "properties" && typeof value === "object" && value !== null) {
27404
+ const props = {};
27405
+ for (const [propKey, propValue] of Object.entries(value)) if (typeof propValue === "object" && propValue !== null) props[propKey] = cleanSchemaForOpenAI(propValue);
27406
+ else props[propKey] = propValue;
27407
+ cleaned[key] = props;
27408
+ } else if (key === "items" && typeof value === "object" && value !== null) cleaned[key] = cleanSchemaForOpenAI(value);
27409
+ else cleaned[key] = value;
27410
+ }
27411
+ return cleaned;
27412
+ }
27413
+ /**
27414
+ * Run an agent turn directly against api.openai.com.
27415
+ *
27416
+ * Maintains multi-turn conversation history per session file.
27417
+ * Falls back to single-turn if history is unavailable.
27418
+ */
27419
+ async function runOpenAIDirectAgent(params) {
27420
+ const started = Date.now();
27421
+ const resolvedModel = resolveModel(params.model);
27422
+ log$2.info(`direct api exec: model=${resolvedModel} promptChars=${params.prompt.length}`);
27423
+ const workspaceDir = resolveRunWorkspaceDir({
27424
+ workspaceDir: params.workspaceDir,
27425
+ sessionKey: params.sessionKey,
27426
+ agentId: params.agentId,
27427
+ config: params.config
27428
+ }).workspaceDir;
27429
+ const executableTools = createAnimaCodingTools({
27430
+ config: params.config,
27431
+ workspaceDir,
27432
+ sessionKey: params.sessionKey,
27433
+ modelProvider: "openai",
27434
+ modelId: resolvedModel
27435
+ });
27436
+ const openaiTools = executableTools.map((t) => ({
27437
+ type: "function",
27438
+ function: {
27439
+ name: t.name,
27440
+ description: t.description,
27441
+ parameters: cleanSchemaForOpenAI(t.parameters ?? {
27442
+ type: "object",
27443
+ properties: {}
27444
+ })
27445
+ }
27446
+ }));
27447
+ const { contextFiles } = await resolveBootstrapContextForRun({
27448
+ workspaceDir,
27449
+ config: params.config,
27450
+ sessionKey: params.sessionKey,
27451
+ sessionId: params.sessionId,
27452
+ warn: makeBootstrapWarn({
27453
+ sessionLabel: params.sessionKey ?? params.sessionId,
27454
+ warn: (msg) => log$2.warn(msg)
27455
+ })
27456
+ });
27457
+ const { defaultAgentId, sessionAgentId } = resolveSessionAgentIds({
27458
+ sessionKey: params.sessionKey,
27459
+ config: params.config
27460
+ });
27461
+ const heartbeatPrompt = sessionAgentId === defaultAgentId ? resolveHeartbeatPrompt(params.config?.agents?.defaults?.heartbeat?.prompt) : void 0;
27462
+ const docsPath = await resolveAnimaDocsPath({
27463
+ workspaceDir,
27464
+ argv1: process.argv[1],
27465
+ cwd: process.cwd(),
27466
+ moduleUrl: import.meta.url
27467
+ });
27468
+ const extraSystemPrompt = appendRunnerCapabilityPrompt(params.extraSystemPrompt, "local-tools");
27469
+ const systemPrompt = buildSystemPrompt({
27470
+ workspaceDir,
27471
+ config: params.config,
27472
+ defaultThinkLevel: params.thinkLevel,
27473
+ extraSystemPrompt,
27474
+ ownerNumbers: params.ownerNumbers,
27475
+ heartbeatPrompt,
27476
+ docsPath: docsPath ?? void 0,
27477
+ tools: executableTools,
27478
+ contextFiles,
27479
+ modelDisplay: `openai/${resolvedModel}`,
27480
+ agentId: sessionAgentId
27481
+ });
27482
+ let history = await loadSessionHistory(params.sessionFile);
27483
+ if (!history) history = {
27484
+ sessionId: params.sessionId,
27485
+ messages: [{
27486
+ role: "system",
27487
+ content: systemPrompt
27488
+ }],
27489
+ createdAt: started,
27490
+ updatedAt: started
27491
+ };
27492
+ else if (history.messages.length > 0 && history.messages[0].role === "system") history.messages[0].content = systemPrompt;
27493
+ history.messages.push({
27494
+ role: "user",
27495
+ content: params.prompt
27496
+ });
27497
+ let finalAssistantText = "";
27498
+ let totalInputTokens = 0;
27499
+ let totalOutputTokens = 0;
27500
+ let isDone = false;
27501
+ let loopCount = 0;
27502
+ const maxLoops = 20;
27503
+ const baseUrl = params.config?.models?.providers?.openai?.baseUrl?.trim() || DEFAULT_OPENAI_BASE_URL;
27504
+ while (!isDone && loopCount < maxLoops) {
27505
+ loopCount++;
27506
+ const requestBody = {
27507
+ model: resolvedModel,
27508
+ messages: history.messages,
27509
+ max_tokens: 8192,
27510
+ temperature: 1,
27511
+ stream: true
27512
+ };
27513
+ if (openaiTools.length > 0) {
27514
+ requestBody.tools = openaiTools;
27515
+ requestBody.tool_choice = "auto";
27516
+ }
27517
+ try {
27518
+ const controller = new AbortController();
27519
+ const timeoutHandle = setTimeout(() => controller.abort(), params.timeoutMs);
27520
+ const url = `${baseUrl}/chat/completions`;
27521
+ const response = await fetch(url, {
27522
+ method: "POST",
27523
+ headers: {
27524
+ "Content-Type": "application/json",
27525
+ Authorization: `Bearer ${params.apiKey}`,
27526
+ "User-Agent": `anima/7.0.0 (openai-direct-runner; ${os.platform()})`
27527
+ },
27528
+ body: JSON.stringify(requestBody),
27529
+ signal: controller.signal
27530
+ });
27531
+ clearTimeout(timeoutHandle);
27532
+ if (!response.ok) {
27533
+ const body = await response.text().catch(() => "");
27534
+ const isAuth = response.status === 401 || response.status === 403;
27535
+ const isRateLimit = response.status === 429;
27536
+ const rateHint = isRateLimit ? " — rate limit hit, will retry next heartbeat." : "";
27537
+ const authHint = isAuth ? " — API key may be invalid. Check OPENAI_API_KEY environment variable." : "";
27538
+ log$2.error(`openai api error: HTTP ${response.status}${authHint}${rateHint}`, {
27539
+ status: response.status,
27540
+ body: body.slice(0, 500)
27541
+ });
27542
+ return {
27543
+ status: "failed",
27544
+ meta: {
27545
+ durationMs: Date.now() - started,
27546
+ error: {
27547
+ message: `HTTP ${response.status}: ${body.slice(0, 200)}${authHint}${rateHint}`,
27548
+ kind: isAuth ? "auth" : isRateLimit ? "rate_limit" : "unknown"
27549
+ }
27550
+ }
27551
+ };
27552
+ }
27553
+ if (!response.body) throw new Error("No response body received from OpenAI API");
27554
+ const bodyStream = Readable.fromWeb(response.body);
27555
+ let buffer = "";
27556
+ let chunkAssistantText = "";
27557
+ const toolCalls = /* @__PURE__ */ new Map();
27558
+ for await (const chunk of bodyStream) {
27559
+ buffer += chunk.toString("utf8");
27560
+ const lines = buffer.split("\n");
27561
+ buffer = lines.pop() ?? "";
27562
+ for (const line of lines) {
27563
+ const trimmed = line.trim();
27564
+ if (!trimmed || !trimmed.startsWith("data: ")) continue;
27565
+ const dataStr = trimmed.slice(6);
27566
+ if (dataStr === "[DONE]") continue;
27567
+ try {
27568
+ const parsed = JSON.parse(dataStr);
27569
+ const delta = parsed.choices?.[0]?.delta;
27570
+ if (delta) {
27571
+ if (typeof delta.content === "string") {
27572
+ chunkAssistantText += delta.content;
27573
+ finalAssistantText += delta.content;
27574
+ if (params.onPartialReply) await params.onPartialReply({ text: finalAssistantText });
27575
+ }
27576
+ if (delta.tool_calls) for (const tc of delta.tool_calls) {
27577
+ const idx = tc.index ?? 0;
27578
+ const existing = toolCalls.get(idx);
27579
+ if (tc.id) toolCalls.set(idx, {
27580
+ id: tc.id,
27581
+ name: tc.function?.name ?? existing?.name ?? "",
27582
+ arguments: (existing?.arguments ?? "") + (tc.function?.arguments ?? "")
27583
+ });
27584
+ else if (existing) {
27585
+ existing.name = existing.name || (tc.function?.name ?? "");
27586
+ existing.arguments += tc.function?.arguments ?? "";
27587
+ }
27588
+ }
27589
+ }
27590
+ if (parsed.usage) {
27591
+ totalInputTokens = Math.max(totalInputTokens, parsed.usage.prompt_tokens ?? 0);
27592
+ totalOutputTokens += parsed.usage.completion_tokens ?? 0;
27593
+ }
27594
+ } catch {}
27595
+ }
27596
+ }
27597
+ if (toolCalls.size > 0) {
27598
+ const assistantToolCalls = Array.from(toolCalls.values()).map((tc) => ({
27599
+ id: tc.id,
27600
+ type: "function",
27601
+ function: {
27602
+ name: tc.name,
27603
+ arguments: tc.arguments
27604
+ }
27605
+ }));
27606
+ const assistantMsg = {
27607
+ role: "assistant",
27608
+ content: chunkAssistantText || null,
27609
+ tool_calls: assistantToolCalls
27610
+ };
27611
+ history.messages.push(assistantMsg);
27612
+ for (const tc of assistantToolCalls) {
27613
+ const tool = executableTools.find((t) => t.name === tc.function.name);
27614
+ let resultContent;
27615
+ if (!tool) resultContent = JSON.stringify({ error: "Tool not found or unauthorized" });
27616
+ else if (!tool.execute) resultContent = JSON.stringify({ error: "Tool execution not implemented" });
27617
+ else try {
27618
+ const callId = crypto.randomUUID();
27619
+ let args = {};
27620
+ try {
27621
+ args = JSON.parse(tc.function.arguments);
27622
+ } catch {
27623
+ args = {};
27624
+ }
27625
+ const result = await tool.execute(callId, args);
27626
+ resultContent = typeof result === "string" ? result : JSON.stringify(result);
27627
+ } catch (err) {
27628
+ resultContent = JSON.stringify({ error: String(err) });
27629
+ }
27630
+ history.messages.push({
27631
+ role: "tool",
27632
+ content: resultContent,
27633
+ tool_call_id: tc.id
27634
+ });
27635
+ }
27636
+ } else {
27637
+ if (chunkAssistantText) history.messages.push({
27638
+ role: "assistant",
27639
+ content: chunkAssistantText
27640
+ });
27641
+ isDone = true;
27642
+ }
27643
+ } catch (err) {
27644
+ const isAbort = err instanceof Error && err.name === "AbortError";
27645
+ const errorKind = isAbort ? "timeout" : "unknown";
27646
+ const errorMsg = isAbort ? `Request timed out after ${params.timeoutMs}ms` : String(err);
27647
+ log$2.error(`openai api error: ${errorMsg}`, { error: String(err) });
27648
+ return {
27649
+ status: isAbort ? "timeout" : "failed",
27650
+ meta: {
27651
+ durationMs: Date.now() - started,
27652
+ error: {
27653
+ message: errorMsg,
27654
+ kind: errorKind
27655
+ }
27656
+ }
27657
+ };
27658
+ }
27659
+ }
27660
+ history.updatedAt = Date.now();
27661
+ await saveSessionHistory(params.sessionFile, history);
27662
+ const durationMs = Date.now() - started;
27663
+ log$2.info(`openai api complete: ${durationMs}ms`, {
27664
+ inputTokens: totalInputTokens,
27665
+ outputTokens: totalOutputTokens,
27666
+ model: resolvedModel
27667
+ });
27668
+ return {
27669
+ status: "completed",
27670
+ output: finalAssistantText,
27671
+ payloads: finalAssistantText ? [{ text: finalAssistantText }] : [],
27672
+ meta: {
27673
+ durationMs,
27674
+ agentMeta: {
27675
+ model: resolvedModel,
27676
+ provider: "openai",
27677
+ usage: {
27678
+ input: totalInputTokens,
27679
+ output: totalOutputTokens
27680
+ }
27681
+ }
27682
+ }
27683
+ };
27684
+ }
27685
+
27191
27686
  //#endregion
27192
27687
  //#region src/agents/noxsoft-runner.ts
27193
27688
  function normalizeEmbeddedProvider(provider) {
@@ -27213,6 +27708,7 @@ async function emitAgentEvent(params, stream, data) {
27213
27708
  function resolveDirectAuthProvider(provider) {
27214
27709
  if (provider === "anthropic" || provider === "claude") return "anthropic";
27215
27710
  if (provider === "google" || provider === "gemini") return "google";
27711
+ if (provider === "openai") return "openai";
27216
27712
  return null;
27217
27713
  }
27218
27714
  function resolveProfileFailureReason(result) {
@@ -27322,8 +27818,7 @@ async function runDirectWithProfileFallback(params) {
27322
27818
  }
27323
27819
  };
27324
27820
  attemptedAuthSources.add(authSourceKey);
27325
- const result = params.directProvider === "anthropic" ? await runAnthropicDirectAgent({
27326
- token: auth.apiKey ?? "",
27821
+ const directRunParams = {
27327
27822
  sessionId: params.sessionId,
27328
27823
  sessionKey: params.sessionKey,
27329
27824
  agentId: params.agentId,
@@ -27339,23 +27834,16 @@ async function runDirectWithProfileFallback(params) {
27339
27834
  ownerNumbers: params.ownerNumbers,
27340
27835
  onPartialReply: params.emitPartial,
27341
27836
  onAssistantMessageStart: params.onAssistantMessageStart
27837
+ };
27838
+ const result = params.directProvider === "anthropic" ? await runAnthropicDirectAgent({
27839
+ ...directRunParams,
27840
+ token: auth.apiKey ?? ""
27841
+ }) : params.directProvider === "openai" ? await runOpenAIDirectAgent({
27842
+ ...directRunParams,
27843
+ apiKey: auth.apiKey ?? ""
27342
27844
  }) : await runGeminiDirectAgent({
27343
- apiKey: auth.apiKey ?? "",
27344
- sessionId: params.sessionId,
27345
- sessionKey: params.sessionKey,
27346
- agentId: params.agentId,
27347
- sessionFile: params.sessionFile,
27348
- workspaceDir: params.workspaceDir,
27349
- config: params.config,
27350
- prompt: params.prompt,
27351
- model: params.model,
27352
- thinkLevel: params.thinkLevel,
27353
- timeoutMs: params.timeoutMs,
27354
- runId: params.runId,
27355
- extraSystemPrompt: params.extraSystemPrompt,
27356
- ownerNumbers: params.ownerNumbers,
27357
- onPartialReply: params.emitPartial,
27358
- onAssistantMessageStart: params.onAssistantMessageStart
27845
+ ...directRunParams,
27846
+ apiKey: auth.apiKey ?? ""
27359
27847
  });
27360
27848
  if (result.status === "completed") {
27361
27849
  if (auth.profileId) {
@@ -27399,7 +27887,7 @@ async function resolveDirectStrategy(provider, config, agentDir) {
27399
27887
  if (auth.apiKey) {
27400
27888
  if (directProvider === "anthropic" && auth.apiKey.startsWith("sk-ant-oat01-")) return null;
27401
27889
  return {
27402
- kind: directProvider === "google" ? "gemini-direct" : "anthropic-direct",
27890
+ kind: directProvider === "google" ? "gemini-direct" : directProvider === "openai" ? "openai-direct" : "anthropic-direct",
27403
27891
  provider
27404
27892
  };
27405
27893
  }
@@ -27533,6 +28021,53 @@ async function runNoxSoftEmbeddedAgent(params) {
27533
28021
  throw err;
27534
28022
  }
27535
28023
  }
28024
+ if (strategy.kind === "openai-direct") {
28025
+ await emitAgentEvent(params, "lifecycle", {
28026
+ phase: "start",
28027
+ startedAt
28028
+ });
28029
+ try {
28030
+ const result = normalizeRunnerResult({
28031
+ result: await runDirectWithProfileFallback({
28032
+ ...params,
28033
+ directProvider: "openai",
28034
+ timeoutMs,
28035
+ runId,
28036
+ emitPartial
28037
+ }),
28038
+ provider: normalizedRequestedRef?.provider ?? provider,
28039
+ model: normalizedRequestedRef?.model,
28040
+ sessionId: params.sessionId
28041
+ });
28042
+ const failure = coerceResultFailure({
28043
+ result,
28044
+ provider: result.meta.agentMeta?.provider ?? provider,
28045
+ model: result.meta.agentMeta?.model
28046
+ });
28047
+ if (failure) {
28048
+ await emitAgentEvent(params, "lifecycle", {
28049
+ phase: "error",
28050
+ startedAt,
28051
+ endedAt: Date.now(),
28052
+ error: failure.message,
28053
+ status: result.status
28054
+ });
28055
+ throw failure;
28056
+ }
28057
+ await emitAgentEvent(params, "lifecycle", {
28058
+ phase: "end",
28059
+ durationMs: Date.now() - startedAt,
28060
+ status: result.status
28061
+ });
28062
+ return result;
28063
+ } catch (err) {
28064
+ await emitAgentEvent(params, "lifecycle", {
28065
+ phase: "error",
28066
+ error: String(err instanceof Error ? err.message : err)
28067
+ });
28068
+ throw err;
28069
+ }
28070
+ }
27536
28071
  await emitAgentEvent(params, "lifecycle", {
27537
28072
  phase: "start",
27538
28073
  startedAt