@nomix-ai/nomix-harness 0.2.5 → 0.2.6
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/README.md +2 -9
- package/dist/assets/web/assets/index-BnapMmQ_.css +1 -0
- package/dist/assets/web/assets/index-Dx7Ws_OC.js +96 -0
- package/dist/assets/web/assets/langs/{php-D-uCvoST.js → php-DDkx9sim.js} +2 -2
- package/dist/{kernel/web-frontend/dist/assets/langs/ruby-DEItuUFs.js → assets/web/assets/langs/ruby-DCxyoPen.js} +2 -2
- package/dist/assets/web/assets/{vendor-Cjbwl5VI.js → vendor-D22_Mp1f.js} +2 -2
- package/dist/assets/web/favicon.svg +8 -0
- package/dist/assets/web/index.html +5 -5
- package/dist/bundles/base/cordis.patch.yml +31 -6
- package/dist/bundles/web-app/cordis.patch.yml +27 -6
- package/dist/cli/bin.js +4 -5
- package/dist/cli/builtin-registry.js +34 -4
- package/dist/cli/{dump-config-d3ECray2.js → dump-config-BEj2GlJo.js} +1 -1
- package/dist/cli/{plugin-Bw9wgrmj.js → plugin-D_gLgCYL.js} +1 -1
- package/dist/cli/profile-boot-BSrYtiQI.js +2 -0
- package/dist/cli/{profile-boot-DFHdh9Xq.js → profile-boot-CByqUxLM.js} +0 -2
- package/dist/cli/runtime.js +0 -2
- package/dist/config/agent-presets/code/agent.cordis.yml +4 -3
- package/dist/config/agent-presets/cordis/agent.cordis.yml +4 -3
- package/dist/config/agent-presets/cordis/skills/editing-cordis-compositions/SKILL.md +13 -2
- package/dist/config/agent-presets/minimal/agent.cordis.yml +27 -1
- package/dist/config/agent-presets/standard/agent.cordis.yml +4 -3
- package/dist/kernel/acp/package.json +1 -1
- package/dist/kernel/agent/package.json +1 -1
- package/dist/kernel/agent-default-model/package.json +1 -1
- package/dist/kernel/agent-instructions/package.json +1 -1
- package/dist/kernel/agent-loop/lib/index.js +33 -10
- package/dist/kernel/agent-loop/lib/types/agent.js +26 -6
- package/dist/kernel/agent-loop/package.json +1 -1
- package/dist/kernel/agent-presets/package.json +1 -1
- package/dist/kernel/agent-tool-presentation/package.json +1 -1
- package/dist/kernel/anonymous-user-id/package.json +1 -1
- package/dist/kernel/api-gateway/lib/client.js +84 -55
- package/dist/kernel/api-gateway/lib/types/client/index.js +93 -61
- package/dist/kernel/api-gateway/package.json +1 -1
- package/dist/kernel/api-remotes/lib/client.js +166 -27
- package/dist/kernel/api-remotes/lib/index.js +1 -1
- package/dist/kernel/api-remotes/lib/types/client/index.d.ts +4 -0
- package/dist/kernel/api-remotes/lib/types/client/index.js +4 -1
- package/dist/kernel/api-remotes/lib/types/remote-events.d.ts +1 -1
- package/dist/kernel/api-remotes/lib/types/remote-events.js +1 -1
- package/dist/kernel/api-remotes/package.json +11 -7
- package/dist/kernel/app-boot/lib/index.js +19 -41
- package/dist/kernel/app-boot/lib/types/index.d.ts +0 -1
- package/dist/kernel/app-boot/lib/types/index.js +2 -3
- package/dist/kernel/app-boot/lib/types/profile.d.ts +15 -12
- package/dist/kernel/app-boot/lib/types/profile.js +15 -25
- package/dist/kernel/app-boot/package.json +1 -1
- package/dist/kernel/atomic-write/lib/index.js +36 -16
- package/dist/kernel/atomic-write/lib/types/index.d.ts +21 -5
- package/dist/kernel/atomic-write/lib/types/index.js +40 -16
- package/dist/kernel/atomic-write/package.json +1 -1
- package/dist/kernel/attachment/lib/index.js +62 -3
- package/dist/kernel/attachment/lib/types/admission.d.ts +15 -0
- package/dist/kernel/attachment/lib/types/admission.js +33 -0
- package/dist/kernel/attachment/lib/types/brand.d.ts +8 -0
- package/dist/kernel/attachment/lib/types/brand.js +8 -0
- package/dist/kernel/attachment/lib/types/error.d.ts +2 -2
- package/dist/kernel/attachment/lib/types/error.js +1 -0
- package/dist/kernel/attachment/lib/types/index.d.ts +23 -5
- package/dist/kernel/attachment/lib/types/index.js +24 -2
- package/dist/kernel/attachment/lib/types/types.d.ts +47 -2
- package/dist/kernel/attachment/package.json +3 -2
- package/dist/kernel/attachment-local/lib/index.js +640 -48
- package/dist/kernel/attachment-local/lib/types/compression-limiter.d.ts +18 -0
- package/dist/kernel/attachment-local/lib/types/compression-limiter.js +43 -0
- package/dist/kernel/attachment-local/lib/types/encoding.d.ts +23 -0
- package/dist/kernel/attachment-local/lib/types/encoding.js +33 -0
- package/dist/kernel/attachment-local/lib/types/image.d.ts +31 -2
- package/dist/kernel/attachment-local/lib/types/image.js +43 -4
- package/dist/kernel/attachment-local/lib/types/index.d.ts +45 -10
- package/dist/kernel/attachment-local/lib/types/index.js +140 -10
- package/dist/kernel/attachment-local/lib/types/normalization.d.ts +44 -0
- package/dist/kernel/attachment-local/lib/types/normalization.js +148 -0
- package/dist/kernel/attachment-local/lib/types/request-image.d.ts +35 -0
- package/dist/kernel/attachment-local/lib/types/request-image.js +208 -0
- package/dist/kernel/attachment-local/lib/types/store.d.ts +36 -9
- package/dist/kernel/attachment-local/lib/types/store.js +60 -24
- package/dist/kernel/attachment-local/package.json +1 -1
- package/dist/kernel/authorization/lib/index.js +248 -0
- package/dist/kernel/authorization/lib/invariant.js +36 -0
- package/dist/kernel/authorization/lib/types/index.d.ts +223 -0
- package/dist/kernel/authorization/lib/types/index.js +299 -0
- package/dist/kernel/authorization/lib/types/invariant.d.ts +16 -0
- package/dist/kernel/authorization/lib/types/invariant.js +38 -0
- package/dist/kernel/authorization/lib/types/types.d.ts +83 -0
- package/dist/kernel/authorization/lib/types/types.js +8 -0
- package/dist/kernel/{client-web-react → authorization}/package.json +19 -16
- package/dist/kernel/base/cordis.patch.yml +31 -6
- package/dist/kernel/base/package.json +3 -1
- package/dist/kernel/bash-local/package.json +1 -1
- package/dist/kernel/bash-sandbox/package.json +1 -1
- package/dist/kernel/brand/package.json +1 -1
- package/dist/kernel/client-connection/lib/client.js +148 -28
- package/dist/kernel/client-connection/lib/index.js +4 -4
- package/dist/kernel/client-connection/lib/types/client/fixture.js +112 -20
- package/dist/kernel/client-connection/lib/types/client/index.d.ts +21 -1
- package/dist/kernel/client-connection/lib/types/client/index.js +3 -2
- package/dist/kernel/client-connection/lib/types/client/rpc.d.ts +4 -1
- package/dist/kernel/client-connection/lib/types/client/rpc.js +4 -2
- package/dist/kernel/client-connection/lib/types/http-bridge.d.ts +2 -2
- package/dist/kernel/client-connection/lib/types/http-bridge.js +3 -3
- package/dist/kernel/client-connection/lib/types/index.d.ts +1 -1
- package/dist/kernel/client-connection/package.json +15 -9
- package/dist/kernel/client-hmr/package.json +1 -1
- package/dist/kernel/client-locale/lib/client.js +48 -9
- package/dist/kernel/client-locale/lib/types/client/index.d.ts +19 -3
- package/dist/kernel/client-locale/lib/types/client/index.js +48 -7
- package/dist/kernel/client-locale/package.json +6 -6
- package/dist/kernel/client-modules/lib/client.js +188 -123
- package/dist/kernel/client-modules/lib/index.js +177 -31
- package/dist/kernel/client-modules/lib/types/client/index.d.ts +19 -8
- package/dist/kernel/client-modules/lib/types/client/index.js +25 -8
- package/dist/kernel/client-modules/lib/types/client/manifest.d.ts +90 -41
- package/dist/kernel/client-modules/lib/types/client/manifest.js +45 -12
- package/dist/kernel/client-modules/lib/types/client/system.d.ts +15 -17
- package/dist/kernel/client-modules/lib/types/client/system.js +85 -56
- package/dist/kernel/client-modules/lib/types/index.d.ts +28 -12
- package/dist/kernel/client-modules/lib/types/index.js +128 -34
- package/dist/kernel/client-modules/package.json +4 -2
- package/dist/kernel/client-runtime/lib/client.js +43 -8
- package/dist/kernel/client-runtime/lib/types/client/contract/session.d.ts +1 -1
- package/dist/kernel/client-runtime/lib/types/client/contract/store.d.ts +1 -1
- package/dist/kernel/client-runtime/lib/types/client/contract/store.js +2 -2
- package/dist/kernel/client-runtime/lib/types/client/index.d.ts +2 -2
- package/dist/kernel/client-runtime/lib/types/client/index.js +3 -3
- package/dist/kernel/client-runtime/lib/types/client/sessions/context-provenance.d.ts +8 -0
- package/dist/kernel/client-runtime/lib/types/client/sessions/context-provenance.js +13 -0
- package/dist/kernel/client-runtime/lib/types/client/sessions/conversation.d.ts +11 -7
- package/dist/kernel/client-runtime/lib/types/client/sessions/projection-store.d.ts +1 -1
- package/dist/kernel/client-runtime/lib/types/client/sessions/session.d.ts +1 -1
- package/dist/kernel/client-runtime/lib/types/client/sessions/session.js +4 -4
- package/dist/kernel/client-runtime/lib/types/client/slots.d.ts +1 -1
- package/dist/kernel/client-runtime/lib/types/client/slots.js +1 -1
- package/dist/kernel/client-runtime/lib/types/client/workspaces/path.d.ts +9 -0
- package/dist/kernel/client-runtime/lib/types/client/workspaces/path.js +27 -1
- package/dist/kernel/client-runtime/package.json +25 -14
- package/dist/kernel/client-ui-agent-preset/lib/client.js +55 -55
- package/dist/kernel/client-ui-agent-preset/lib/types/client/index.js +2 -2
- package/dist/kernel/client-ui-agent-preset/lib/types/client/settings-store.d.ts +7 -1
- package/dist/kernel/client-ui-agent-preset/lib/types/client/settings-store.js +21 -20
- package/dist/kernel/client-ui-agent-preset/package.json +2 -7
- package/dist/kernel/client-ui-attachment/lib/client.js +782 -0
- package/dist/kernel/client-ui-attachment/lib/index.js +5 -505
- package/dist/kernel/client-ui-attachment/lib/invariant.js +2 -3
- package/dist/kernel/client-ui-attachment/lib/types/client/ComposerAttachments.d.ts +4 -0
- package/dist/kernel/client-ui-attachment/lib/types/client/ComposerAttachments.js +85 -0
- package/dist/kernel/client-ui-attachment/lib/types/client/MessageImages.d.ts +4 -0
- package/dist/kernel/client-ui-attachment/lib/types/client/MessageImages.js +8 -0
- package/dist/kernel/client-ui-attachment/lib/types/client/index.d.ts +7 -0
- package/dist/kernel/client-ui-attachment/lib/types/client/index.js +16 -0
- package/dist/kernel/client-ui-attachment/lib/types/client/labels.d.ts +35 -0
- package/dist/kernel/client-ui-attachment/lib/types/client/labels.js +52 -0
- package/dist/kernel/client-ui-attachment/lib/types/index.d.ts +3 -15
- package/dist/kernel/client-ui-attachment/lib/types/index.js +3 -11
- package/dist/kernel/client-ui-attachment/lib/types/invariant.js +2 -3
- package/dist/kernel/client-ui-attachment/package.json +32 -9
- package/dist/kernel/client-ui-brand-official/lib/client.js +50 -0
- package/dist/kernel/client-ui-brand-official/lib/index.js +9 -0
- package/dist/kernel/{client-web-react → client-ui-brand-official}/lib/invariant.js +6 -8
- package/dist/kernel/client-ui-brand-official/lib/types/client/Brand.d.ts +16 -0
- package/dist/kernel/client-ui-brand-official/lib/types/client/Brand.js +18 -0
- package/dist/kernel/client-ui-brand-official/lib/types/client/index.d.ts +10 -0
- package/dist/kernel/client-ui-brand-official/lib/types/client/index.js +17 -0
- package/dist/kernel/client-ui-brand-official/lib/types/index.d.ts +7 -0
- package/dist/kernel/client-ui-brand-official/lib/types/index.js +7 -0
- package/dist/kernel/client-ui-brand-official/lib/types/invariant.d.ts +16 -0
- package/dist/kernel/{client-web-react → client-ui-brand-official}/lib/types/invariant.js +6 -8
- package/dist/kernel/client-ui-brand-official/package.json +72 -0
- package/dist/kernel/client-ui-commands/lib/client.js +44 -15
- package/dist/kernel/client-ui-commands/lib/types/client/locales.d.ts +2 -0
- package/dist/kernel/client-ui-commands/lib/types/client/locales.js +2 -0
- package/dist/kernel/client-ui-commands/lib/types/client/service.d.ts +11 -1
- package/dist/kernel/client-ui-commands/lib/types/client/service.js +39 -7
- package/dist/kernel/client-ui-commands/package.json +2 -5
- package/dist/kernel/client-ui-conversation/lib/client.js +949 -531
- package/dist/kernel/client-ui-conversation/lib/types/client/apply.js +6 -4
- package/dist/kernel/client-ui-conversation/lib/types/client/chat/AssistantMarkdown.d.ts +4 -5
- package/dist/kernel/client-ui-conversation/lib/types/client/chat/AssistantMarkdown.js +6 -6
- package/dist/kernel/client-ui-conversation/lib/types/client/chat/AssistantNodeView.d.ts +1 -1
- package/dist/kernel/client-ui-conversation/lib/types/client/chat/AssistantNodeView.js +2 -2
- package/dist/kernel/client-ui-conversation/lib/types/client/chat/ChatNodeSeat.d.ts +1 -1
- package/dist/kernel/client-ui-conversation/lib/types/client/chat/ChatNodeSeat.js +5 -3
- package/dist/kernel/client-ui-conversation/lib/types/client/chat/ChatView.js +53 -10
- package/dist/kernel/client-ui-conversation/lib/types/client/chat/ContextInjectionRow.js +4 -1
- package/dist/kernel/client-ui-conversation/lib/types/client/chat/MessageItem.d.ts +4 -5
- package/dist/kernel/client-ui-conversation/lib/types/client/chat/MessageItem.js +46 -16
- package/dist/kernel/client-ui-conversation/lib/types/client/chat/StatsLine.d.ts +5 -3
- package/dist/kernel/client-ui-conversation/lib/types/client/chat/StatsLine.js +54 -5
- package/dist/kernel/client-ui-conversation/lib/types/client/contract/slots.d.ts +90 -8
- package/dist/kernel/client-ui-conversation/lib/types/client/conversation-nodes/assistant.js +1 -0
- package/dist/kernel/client-ui-conversation/lib/types/client/conversation-nodes/chat-snapshot-builder.d.ts +1 -0
- package/dist/kernel/client-ui-conversation/lib/types/client/conversation-nodes/chat-snapshot-builder.js +95 -6
- package/dist/kernel/client-ui-conversation/lib/types/client/conversation-nodes/message.d.ts +11 -3
- package/dist/kernel/client-ui-conversation/lib/types/client/conversation-nodes/turn-error.d.ts +6 -3
- package/dist/kernel/client-ui-conversation/lib/types/client/conversation-nodes/turn-error.js +10 -26
- package/dist/kernel/client-ui-conversation/lib/types/client/image-labels.d.ts +1 -33
- package/dist/kernel/client-ui-conversation/lib/types/client/image-labels.js +5 -54
- package/dist/kernel/client-ui-conversation/lib/types/client/index.d.ts +1 -1
- package/dist/kernel/client-ui-conversation/lib/types/client/input/contract.d.ts +17 -14
- package/dist/kernel/client-ui-conversation/lib/types/client/input/decorations.d.ts +13 -5
- package/dist/kernel/client-ui-conversation/lib/types/client/input/decorations.js +26 -10
- package/dist/kernel/client-ui-conversation/lib/types/client/input/facade.d.ts +34 -14
- package/dist/kernel/client-ui-conversation/lib/types/client/input/facade.js +116 -34
- package/dist/kernel/client-ui-conversation/lib/types/client/input/hub.d.ts +1 -1
- package/dist/kernel/client-ui-conversation/lib/types/client/input/hub.js +21 -19
- package/dist/kernel/client-ui-conversation/lib/types/client/input/machine.d.ts +35 -14
- package/dist/kernel/client-ui-conversation/lib/types/client/input/machine.js +71 -34
- package/dist/kernel/client-ui-conversation/lib/types/client/locales.d.ts +16 -0
- package/dist/kernel/client-ui-conversation/lib/types/client/locales.js +16 -0
- package/dist/kernel/client-ui-conversation/lib/types/client/reference/ReferenceIcon.d.ts +16 -0
- package/dist/kernel/client-ui-conversation/lib/types/client/reference/ReferenceIcon.js +16 -0
- package/dist/kernel/client-ui-conversation/lib/types/client/service.d.ts +14 -1
- package/dist/kernel/client-ui-conversation/lib/types/client/service.js +26 -6
- package/dist/kernel/client-ui-conversation/lib/types/client/skeleton/ConversationRoot.js +1 -1
- package/dist/kernel/client-ui-conversation/lib/types/client/skeleton/ConversationSession.js +18 -3
- package/dist/kernel/client-ui-conversation/lib/types/client/skeleton/EmptyHero.d.ts +3 -1
- package/dist/kernel/client-ui-conversation/lib/types/client/skeleton/EmptyHero.js +4 -2
- package/dist/kernel/client-ui-conversation/lib/types/client/skeleton/InputBar.js +141 -126
- package/dist/kernel/client-ui-conversation/package.json +9 -8
- package/dist/kernel/client-ui-cordis/lib/client.js +48 -48
- package/dist/kernel/client-ui-cordis/package.json +2 -5
- package/dist/kernel/client-ui-deliverables/lib/client.js +5 -5
- package/dist/kernel/client-ui-deliverables/package.json +4 -6
- package/dist/kernel/client-ui-directory-picker-browse/lib/client.js +26 -26
- package/dist/kernel/client-ui-directory-picker-browse/package.json +2 -5
- package/dist/kernel/client-ui-directory-picker-native/package.json +2 -5
- package/dist/kernel/client-ui-goal/lib/client.js +8 -8
- package/dist/kernel/client-ui-goal/package.json +6 -5
- package/dist/kernel/client-ui-input-trigger/lib/client.js +82 -26
- package/dist/kernel/client-ui-input-trigger/lib/types/client/MenuView.js +13 -9
- package/dist/kernel/client-ui-input-trigger/lib/types/client/controller.d.ts +5 -3
- package/dist/kernel/client-ui-input-trigger/lib/types/client/controller.js +19 -7
- package/dist/kernel/client-ui-input-trigger/lib/types/client/index.d.ts +1 -1
- package/dist/kernel/client-ui-input-trigger/lib/types/core/contract.d.ts +7 -2
- package/dist/kernel/client-ui-input-trigger/lib/types/core/detect.d.ts +4 -4
- package/dist/kernel/client-ui-input-trigger/lib/types/core/detect.js +24 -6
- package/dist/kernel/client-ui-input-trigger/lib/types/core/menu.d.ts +15 -2
- package/dist/kernel/client-ui-input-trigger/lib/types/core/menu.js +13 -4
- package/dist/kernel/client-ui-input-trigger/lib/types/types.d.ts +52 -8
- package/dist/kernel/client-ui-input-trigger/package.json +4 -5
- package/dist/kernel/client-ui-jobs/lib/client.js +10 -10
- package/dist/kernel/client-ui-jobs/package.json +3 -7
- package/dist/kernel/client-ui-layout/lib/client.js +3 -3
- package/dist/kernel/client-ui-layout/package.json +2 -4
- package/dist/kernel/client-ui-message-feedback/lib/client.js +174 -58
- package/dist/kernel/client-ui-message-feedback/lib/types/client/MessageFeedbackActions.d.ts +9 -3
- package/dist/kernel/client-ui-message-feedback/lib/types/client/MessageFeedbackActions.js +164 -25
- package/dist/kernel/client-ui-message-feedback/lib/types/client/locales.d.ts +2 -0
- package/dist/kernel/client-ui-message-feedback/lib/types/client/locales.js +2 -0
- package/dist/kernel/client-ui-message-feedback/package.json +3 -5
- package/dist/kernel/client-ui-model-selection/lib/client.js +18 -18
- package/dist/kernel/client-ui-model-selection/package.json +7 -9
- package/dist/kernel/client-ui-permission-presets/lib/client.js +97 -83
- package/dist/kernel/client-ui-permission-presets/lib/types/client/index.js +6 -19
- package/dist/kernel/client-ui-permission-presets/lib/types/client/settings-store.d.ts +27 -18
- package/dist/kernel/client-ui-permission-presets/lib/types/client/settings-store.js +95 -68
- package/dist/kernel/client-ui-permission-presets/package.json +2 -8
- package/dist/kernel/client-ui-plan/lib/client.js +1 -1
- package/dist/kernel/client-ui-plan/lib/types/client/index.js +1 -1
- package/dist/kernel/client-ui-plan/package.json +2 -6
- package/dist/kernel/client-ui-primitives/lib/Button.module.css +79 -0
- package/dist/kernel/client-ui-primitives/lib/ConnectionBanner.module.css +13 -0
- package/dist/kernel/client-ui-primitives/lib/DiffBlock.module.css +107 -0
- package/dist/kernel/client-ui-primitives/lib/DisclosureRow.module.css +69 -0
- package/dist/kernel/client-ui-primitives/lib/HoverCard.module.css +54 -0
- package/dist/kernel/client-ui-primitives/lib/Input.module.css +38 -0
- package/dist/kernel/client-ui-primitives/lib/JsonTree.module.css +222 -0
- package/dist/kernel/client-ui-primitives/lib/Menu.module.css +242 -0
- package/dist/kernel/client-ui-primitives/lib/Modal.module.css +103 -0
- package/dist/kernel/client-ui-primitives/lib/OnboardingSurface.module.css +29 -0
- package/dist/kernel/client-ui-primitives/lib/Pill.module.css +27 -0
- package/dist/kernel/client-ui-primitives/lib/ReadBlock.module.css +117 -0
- package/dist/kernel/client-ui-primitives/lib/RiskConfirmation.module.css +73 -0
- package/dist/kernel/client-ui-primitives/lib/SearchBlock.module.css +120 -0
- package/dist/kernel/client-ui-primitives/lib/StateDot.module.css +65 -0
- package/dist/kernel/client-ui-primitives/lib/TerminalBlock.module.css +211 -0
- package/dist/kernel/client-ui-primitives/lib/Toast.module.css +70 -0
- package/dist/kernel/client-ui-primitives/lib/Tooltip.module.css +49 -0
- package/dist/kernel/client-ui-primitives/lib/WebBlock.module.css +130 -0
- package/dist/kernel/client-ui-primitives/lib/index.js +291 -261
- package/dist/kernel/client-ui-primitives/lib/invariant.js +2 -0
- package/dist/kernel/client-ui-primitives/lib/markdown/CodeBlock.module.css +96 -0
- package/dist/kernel/client-ui-primitives/lib/markdown/JsonBlock.module.css +32 -0
- package/dist/kernel/client-ui-primitives/lib/markdown/MarkdownText.module.css +304 -0
- package/dist/kernel/client-ui-primitives/lib/markdown/MessageText.module.css +9 -0
- package/dist/kernel/client-ui-primitives/lib/types/BrandWordmark.d.ts +7 -1
- package/dist/kernel/client-ui-primitives/lib/types/BrandWordmark.js +4 -2
- package/dist/kernel/client-ui-primitives/lib/types/index.d.ts +4 -1
- package/dist/kernel/client-ui-primitives/lib/types/index.js +2 -1
- package/dist/kernel/client-ui-primitives/lib/types/markdown/render.d.ts +2 -0
- package/dist/kernel/client-ui-primitives/lib/types/markdown/render.js +10 -2
- package/dist/kernel/client-ui-primitives/lib/types/useAnchoredPosition.d.ts +32 -0
- package/dist/kernel/client-ui-primitives/lib/types/useAnchoredPosition.js +69 -0
- package/dist/kernel/client-ui-primitives/package.json +2 -1
- package/dist/kernel/client-ui-reference/lib/client.js +149 -0
- package/dist/kernel/client-ui-reference/lib/index.js +11 -0
- package/dist/kernel/{client-schema-form → client-ui-reference}/lib/invariant.js +7 -8
- package/dist/kernel/client-ui-reference/lib/types/client/index.d.ts +9 -0
- package/dist/kernel/client-ui-reference/lib/types/client/index.js +106 -0
- package/dist/kernel/client-ui-reference/lib/types/client/locales.d.ts +30 -0
- package/dist/kernel/client-ui-reference/lib/types/client/locales.js +22 -0
- package/dist/kernel/client-ui-reference/lib/types/index.d.ts +9 -0
- package/dist/kernel/client-ui-reference/lib/types/index.js +9 -0
- package/dist/kernel/{client-schema-form → client-ui-reference}/lib/types/invariant.d.ts +3 -3
- package/dist/kernel/{client-schema-form → client-ui-reference}/lib/types/invariant.js +7 -8
- package/dist/kernel/client-ui-reference/package.json +77 -0
- package/dist/kernel/client-ui-renderer/lib/client.js +989 -0
- package/dist/kernel/client-ui-renderer/lib/index.js +6 -0
- package/dist/kernel/client-ui-renderer/lib/invariant.js +23 -0
- package/dist/kernel/{client-web/lib/types → client-ui-renderer/lib/types/client}/DocumentTitle.d.ts +4 -4
- package/dist/kernel/client-ui-renderer/lib/types/client/DocumentTitle.js +17 -0
- package/dist/kernel/client-ui-renderer/lib/types/client/app.d.ts +18 -0
- package/dist/kernel/{client-web/lib/types → client-ui-renderer/lib/types/client}/app.js +5 -5
- package/dist/kernel/{client-web-react/lib/types → client-ui-renderer/lib/types/client}/bind.d.ts +1 -1
- package/dist/kernel/client-ui-renderer/lib/types/client/index.d.ts +29 -0
- package/dist/kernel/client-ui-renderer/lib/types/client/index.js +51 -0
- package/dist/kernel/{client-web-react/lib/types → client-ui-renderer/lib/types/client}/scoped-slots.d.ts +1 -1
- package/dist/kernel/{client-web-react/lib/types → client-ui-renderer/lib/types/client}/scoped-slots.js +1 -1
- package/dist/kernel/{client-web-react/lib/types → client-ui-renderer/lib/types/client}/session-provider.d.ts +1 -1
- package/dist/kernel/client-ui-renderer/lib/types/index.d.ts +4 -0
- package/dist/kernel/client-ui-renderer/lib/types/index.js +4 -0
- package/dist/kernel/{client-web-react → client-ui-renderer}/lib/types/invariant.d.ts +3 -3
- package/dist/kernel/client-ui-renderer/lib/types/invariant.js +22 -0
- package/dist/kernel/client-ui-renderer/package.json +71 -0
- package/dist/kernel/client-ui-settings/lib/client.js +1177 -67
- package/dist/kernel/client-ui-settings/lib/types/client/index.d.ts +20 -12
- package/dist/kernel/client-ui-settings/lib/types/client/index.js +25 -6
- package/dist/kernel/client-ui-settings/lib/types/client/schema.d.ts +72 -0
- package/dist/kernel/client-ui-settings/lib/types/client/schema.js +152 -0
- package/dist/kernel/client-ui-settings/lib/types/client/settings-mirror.d.ts +118 -0
- package/dist/kernel/client-ui-settings/lib/types/client/settings-mirror.js +160 -0
- package/dist/kernel/client-ui-settings/lib/types/client/settings-scope.d.ts +51 -24
- package/dist/kernel/client-ui-settings/lib/types/client/settings-scope.js +88 -71
- package/dist/kernel/client-ui-settings/package.json +7 -7
- package/dist/kernel/client-ui-settings-general/lib/client.js +60 -64
- package/dist/kernel/client-ui-settings-general/lib/types/client/SettingsDocumentAction.d.ts +7 -6
- package/dist/kernel/client-ui-settings-general/lib/types/client/index.js +10 -11
- package/dist/kernel/client-ui-settings-general/lib/types/client/settings-document-store.d.ts +13 -11
- package/dist/kernel/client-ui-settings-general/lib/types/client/settings-document-store.js +37 -40
- package/dist/kernel/client-ui-settings-general/package.json +4 -8
- package/dist/kernel/client-ui-settings-models/lib/client.js +280 -210
- package/dist/kernel/client-ui-settings-models/lib/types/client/DeepSeekOnboardingDialog.d.ts +3 -0
- package/dist/kernel/client-ui-settings-models/lib/types/client/DeepSeekOnboardingDialog.js +2 -2
- package/dist/kernel/client-ui-settings-models/lib/types/client/ModelListEditor.js +11 -1
- package/dist/kernel/client-ui-settings-models/lib/types/client/ModelsSection.d.ts +10 -5
- package/dist/kernel/client-ui-settings-models/lib/types/client/ModelsSection.js +9 -6
- package/dist/kernel/client-ui-settings-models/lib/types/client/ProviderEditor.d.ts +3 -0
- package/dist/kernel/client-ui-settings-models/lib/types/client/ProviderEditor.js +30 -29
- package/dist/kernel/client-ui-settings-models/lib/types/client/index.js +27 -22
- package/dist/kernel/client-ui-settings-models/lib/types/client/locales.d.ts +2 -0
- package/dist/kernel/client-ui-settings-models/lib/types/client/locales.js +4 -0
- package/dist/kernel/client-ui-settings-models/lib/types/client/schema-operations.d.ts +10 -0
- package/dist/kernel/client-ui-settings-models/lib/types/client/schema-operations.js +17 -0
- package/dist/kernel/client-ui-settings-models/lib/types/client/store.d.ts +15 -7
- package/dist/kernel/client-ui-settings-models/lib/types/client/store.js +30 -21
- package/dist/kernel/client-ui-settings-models/lib/types/client/welcome-store.d.ts +35 -18
- package/dist/kernel/client-ui-settings-models/lib/types/client/welcome-store.js +89 -82
- package/dist/kernel/client-ui-settings-models/package.json +3 -8
- package/dist/kernel/client-ui-settings-plugin-inventory/lib/client.js +11 -11
- package/dist/kernel/client-ui-settings-plugin-inventory/package.json +2 -5
- package/dist/kernel/client-ui-settings-plugins/lib/client.js +42 -65
- package/dist/kernel/client-ui-settings-plugins/lib/types/client/index.js +5 -8
- package/dist/kernel/client-ui-settings-plugins/lib/types/client/tab-store.d.ts +8 -17
- package/dist/kernel/client-ui-settings-plugins/lib/types/client/tab-store.js +22 -44
- package/dist/kernel/client-ui-settings-plugins/package.json +2 -7
- package/dist/kernel/client-ui-sidebar/lib/client.js +50 -20
- package/dist/kernel/client-ui-sidebar/lib/types/client/SidebarRoot.js +7 -3
- package/dist/kernel/client-ui-sidebar/lib/types/client/contract/slots.d.ts +30 -1
- package/dist/kernel/client-ui-sidebar/lib/types/client/index.d.ts +1 -1
- package/dist/kernel/client-ui-sidebar/lib/types/client/index.js +2 -0
- package/dist/kernel/client-ui-sidebar/package.json +2 -4
- package/dist/kernel/client-ui-skill/lib/client.js +12 -12
- package/dist/kernel/client-ui-skill/package.json +2 -5
- package/dist/kernel/client-ui-slots/lib/index.js +2 -0
- package/dist/kernel/client-ui-slots/lib/invariant.js +2 -0
- package/dist/kernel/client-ui-slots/lib/types/renderer.d.ts +1 -1
- package/dist/kernel/client-ui-slots/lib/types/store.d.ts +1 -1
- package/dist/kernel/client-ui-slots/package.json +1 -1
- package/dist/kernel/client-ui-subagent/lib/client.js +289 -157
- package/dist/kernel/client-ui-subagent/lib/types/client/SubagentHeaderLineage.d.ts +18 -0
- package/dist/kernel/client-ui-subagent/lib/types/client/{SubagentCatalogAction.js → SubagentHeaderLineage.js} +153 -25
- package/dist/kernel/client-ui-subagent/lib/types/client/index.d.ts +4 -16
- package/dist/kernel/client-ui-subagent/lib/types/client/index.js +7 -45
- package/dist/kernel/client-ui-subagent/lib/types/client/locales.d.ts +1 -0
- package/dist/kernel/client-ui-subagent/lib/types/client/locales.js +2 -0
- package/dist/kernel/client-ui-subagent/package.json +6 -8
- package/dist/kernel/client-ui-theme/lib/client.js +46 -3
- package/dist/kernel/client-ui-theme/lib/index.js +22 -23
- package/dist/kernel/client-ui-theme/lib/types/boot-theme.d.ts +9 -10
- package/dist/kernel/client-ui-theme/lib/types/boot-theme.js +12 -19
- package/dist/kernel/client-ui-theme/lib/types/client/index.d.ts +1 -1
- package/dist/kernel/client-ui-theme/lib/types/client/index.js +3 -1
- package/dist/kernel/client-ui-theme/lib/types/client/styles.d.ts +7 -0
- package/dist/kernel/client-ui-theme/lib/types/client/styles.js +32 -0
- package/dist/kernel/client-ui-theme/lib/types/index.d.ts +4 -3
- package/dist/kernel/client-ui-theme/lib/types/index.js +7 -6
- package/dist/kernel/client-ui-theme/package.json +4 -6
- package/dist/kernel/client-ui-tool/lib/client.js +105 -65
- package/dist/kernel/client-ui-tool/lib/types/client/apply.d.ts +1 -2
- package/dist/kernel/client-ui-tool/lib/types/client/apply.js +6 -2
- package/dist/kernel/client-ui-tool/lib/types/client/contract/slots.d.ts +13 -3
- package/dist/kernel/client-ui-tool/lib/types/client/index.d.ts +1 -1
- package/dist/kernel/client-ui-tool/lib/types/client/tool/ToolCallTree.d.ts +1 -1
- package/dist/kernel/client-ui-tool/lib/types/client/tool/ToolCallTree.js +8 -6
- package/dist/kernel/client-ui-tool/lib/types/client/tool/ToolDetails.d.ts +2 -9
- package/dist/kernel/client-ui-tool/lib/types/client/tool/ToolDetails.js +4 -3
- package/dist/kernel/client-ui-tool/lib/types/client/tool/models/read-card-model.d.ts +4 -18
- package/dist/kernel/client-ui-tool/lib/types/client/tool/models/read-card-model.js +21 -4
- package/dist/kernel/client-ui-tool/lib/types/client/tool/models/tool-call-model.d.ts +2 -9
- package/dist/kernel/client-ui-tool/lib/types/client/tool/models/tool-call-model.js +22 -2
- package/dist/kernel/client-ui-tool/lib/types/client/tool/toolviews/GenericToolCard.d.ts +1 -1
- package/dist/kernel/client-ui-tool/lib/types/client/tool/toolviews/GenericToolCard.js +3 -3
- package/dist/kernel/client-ui-tool/lib/types/client/tool/toolviews/file-mutation-row.d.ts +1 -1
- package/dist/kernel/client-ui-tool/lib/types/client/tool/toolviews/file-mutation-row.js +2 -2
- package/dist/kernel/client-ui-tool/lib/types/client/tool/toolviews/read-row.d.ts +1 -1
- package/dist/kernel/client-ui-tool/lib/types/client/tool/toolviews/read-row.js +3 -3
- package/dist/kernel/client-ui-tool/package.json +4 -6
- package/dist/kernel/client-ui-trajectory/lib/client.js +144 -143
- package/dist/kernel/client-ui-trajectory/lib/types/client/trajectory-assistant-definition.js +2 -1
- package/dist/kernel/client-ui-trajectory/package.json +2 -4
- package/dist/kernel/client-ui-user-questions/lib/client.js +73 -36
- package/dist/kernel/client-ui-user-questions/lib/types/client/QuestionComposer.js +24 -6
- package/dist/kernel/client-ui-user-questions/package.json +12 -10
- package/dist/kernel/client-ui-workflow-run/lib/client.js +262 -87
- package/dist/kernel/client-ui-workflow-run/lib/types/client/WorkflowRunPanel.js +162 -23
- package/dist/kernel/client-ui-workflow-run/package.json +3 -7
- package/dist/kernel/client-ui-workspace/lib/client.js +96 -60
- package/dist/kernel/client-ui-workspace/lib/types/client/WorkspaceBrowser.d.ts +1 -1
- package/dist/kernel/client-ui-workspace/lib/types/client/WorkspaceBrowser.js +38 -6
- package/dist/kernel/client-ui-workspace/lib/types/client/contract/slots.d.ts +9 -7
- package/dist/kernel/client-ui-workspace/lib/types/client/index.js +4 -2
- package/dist/kernel/client-ui-workspace/lib/types/client/rows/Rows.d.ts +4 -1
- package/dist/kernel/client-ui-workspace/lib/types/client/rows/Rows.js +5 -3
- package/dist/kernel/client-ui-workspace/package.json +6 -4
- package/dist/kernel/client-web/lib/base.css +41 -0
- package/dist/kernel/client-web/lib/boot-page.module.css +104 -0
- package/dist/kernel/client-web/lib/index.js +154 -308
- package/dist/kernel/client-web/lib/invariant.js +2 -0
- package/dist/kernel/client-web/lib/types/boot-page.d.ts +46 -0
- package/dist/kernel/client-web/lib/types/boot-page.js +93 -0
- package/dist/kernel/client-web/lib/types/boot.d.ts +20 -33
- package/dist/kernel/client-web/lib/types/boot.js +76 -149
- package/dist/kernel/client-web/lib/types/index.d.ts +5 -11
- package/dist/kernel/client-web/lib/types/index.js +4 -10
- package/dist/kernel/client-web/lib/types/loader-status.d.ts +3 -51
- package/dist/kernel/client-web/lib/types/loader-status.js +0 -35
- package/dist/kernel/client-web/lib/types/platform.d.ts +3 -1
- package/dist/kernel/client-web/lib/types/platform.js +4 -3
- package/dist/kernel/client-web/lib/types/seed.js +0 -6
- package/dist/kernel/client-web/package.json +8 -15
- package/dist/kernel/cmdline/package.json +1 -1
- package/dist/kernel/code-runtime/package.json +1 -1
- package/dist/kernel/code-runtime-python/lib/index.js +413 -0
- package/dist/kernel/code-runtime-python/lib/invariant.js +24 -0
- package/dist/kernel/code-runtime-python/lib/types/index.d.ts +12 -0
- package/dist/kernel/code-runtime-python/lib/types/index.js +11 -0
- package/dist/kernel/code-runtime-python/lib/types/invariant.d.ts +16 -0
- package/dist/kernel/code-runtime-python/lib/types/invariant.js +23 -0
- package/dist/kernel/code-runtime-python/lib/types/protocol.d.ts +329 -0
- package/dist/kernel/code-runtime-python/lib/types/protocol.js +496 -0
- package/dist/kernel/{client-schema-form → code-runtime-python}/package.json +11 -14
- package/dist/kernel/code-runtime-python/py/protocol.py +138 -0
- package/dist/kernel/code-runtime-worker-thread/package.json +1 -1
- package/dist/kernel/command-compact/package.json +1 -1
- package/dist/kernel/command-feedback/package.json +1 -1
- package/dist/kernel/command-goal/lib/index.js +40 -6
- package/dist/kernel/command-goal/lib/types/index.js +35 -6
- package/dist/kernel/command-goal/package.json +2 -1
- package/dist/kernel/commands/lib/index.js +78 -21
- package/dist/kernel/commands/lib/typert.host.js +53 -9
- package/dist/kernel/commands/lib/typert.remote-client.d.ts +4 -3
- package/dist/kernel/commands/lib/typert.remote-client.js +18 -2
- package/dist/kernel/commands/lib/types/index.d.ts +20 -1
- package/dist/kernel/commands/lib/types/index.js +77 -20
- package/dist/kernel/commands/lib/types/types.d.ts +8 -0
- package/dist/kernel/commands/package.json +5 -1
- package/dist/kernel/compaction/package.json +1 -1
- package/dist/kernel/compaction-basic/package.json +1 -1
- package/dist/kernel/compaction-tool-result-pruner/package.json +1 -1
- package/dist/kernel/cordis/package.json +3 -1
- package/dist/kernel/cordis-client-runner/lib/client.js +171 -37
- package/dist/kernel/cordis-client-runner/lib/types/client/api-catalog.js +3 -3
- package/dist/kernel/cordis-client-runner/lib/types/client/slot-catalog.js +208 -30
- package/dist/kernel/cordis-client-runner/package.json +2 -5
- package/dist/kernel/cordis-host-runner/lib/index.js +28 -5
- package/dist/kernel/cordis-host-runner/lib/typert.host.js +54 -6
- package/dist/kernel/cordis-host-runner/lib/types/sandbox.d.ts +9 -3
- package/dist/kernel/cordis-host-runner/lib/types/sandbox.js +34 -6
- package/dist/kernel/cordis-host-runner/package.json +1 -1
- package/dist/kernel/cordis-plugin-group/package.json +3 -1
- package/dist/kernel/cordis-plugin-hmr/lib/types/index.js +1 -1
- package/dist/kernel/cordis-plugin-hmr/package.json +3 -1
- package/dist/kernel/cordis-plugin-include/lib/index.js +2 -2
- package/dist/kernel/cordis-plugin-include/lib/types/index.d.ts +2 -2
- package/dist/kernel/cordis-plugin-include/lib/types/index.js +2 -2
- package/dist/kernel/cordis-plugin-include/package.json +3 -1
- package/dist/kernel/cordis-plugin-loader/package.json +3 -1
- package/dist/kernel/cordis-plugin-logger-console/package.json +3 -1
- package/dist/kernel/cordis-plugin-timer/package.json +3 -1
- package/dist/kernel/cosmokit/package.json +3 -1
- package/dist/kernel/credentials/lib/index.js +104 -13
- package/dist/kernel/credentials/lib/invariant.js +3 -3
- package/dist/kernel/credentials/lib/types/index.d.ts +136 -7
- package/dist/kernel/credentials/lib/types/index.js +114 -15
- package/dist/kernel/credentials/lib/types/invariant.js +3 -3
- package/dist/kernel/credentials/lib/types/types.d.ts +58 -5
- package/dist/kernel/credentials/lib/types/types.js +4 -4
- package/dist/kernel/credentials/package.json +1 -1
- package/dist/kernel/credentials-local/lib/index.js +387 -29
- package/dist/kernel/credentials-local/lib/invariant.js +1 -1
- package/dist/kernel/credentials-local/lib/types/index.d.ts +57 -12
- package/dist/kernel/credentials-local/lib/types/index.js +445 -30
- package/dist/kernel/credentials-local/lib/types/invariant.js +1 -1
- package/dist/kernel/credentials-local/package.json +1 -1
- package/dist/kernel/e2b/package.json +1 -1
- package/dist/kernel/experimental-agent-team/lib/index.js +1728 -0
- package/dist/kernel/experimental-agent-team/lib/invariant.js +354 -0
- package/dist/kernel/experimental-agent-team/lib/types/activity.d.ts +23 -0
- package/dist/kernel/experimental-agent-team/lib/types/activity.js +85 -0
- package/dist/kernel/experimental-agent-team/lib/types/error.d.ts +13 -0
- package/dist/kernel/experimental-agent-team/lib/types/error.js +23 -0
- package/dist/kernel/experimental-agent-team/lib/types/fold.d.ts +44 -0
- package/dist/kernel/experimental-agent-team/lib/types/fold.js +243 -0
- package/dist/kernel/experimental-agent-team/lib/types/index.d.ts +115 -0
- package/dist/kernel/experimental-agent-team/lib/types/index.js +205 -0
- package/dist/kernel/experimental-agent-team/lib/types/invariant.d.ts +9 -0
- package/dist/kernel/experimental-agent-team/lib/types/invariant.js +29 -0
- package/dist/kernel/experimental-agent-team/lib/types/journal.d.ts +39 -0
- package/dist/kernel/experimental-agent-team/lib/types/journal.js +59 -0
- package/dist/kernel/experimental-agent-team/lib/types/lifecycle.d.ts +33 -0
- package/dist/kernel/experimental-agent-team/lib/types/lifecycle.js +85 -0
- package/dist/kernel/experimental-agent-team/lib/types/mailbox.d.ts +79 -0
- package/dist/kernel/experimental-agent-team/lib/types/mailbox.js +303 -0
- package/dist/kernel/experimental-agent-team/lib/types/roster.d.ts +113 -0
- package/dist/kernel/experimental-agent-team/lib/types/roster.js +445 -0
- package/dist/kernel/experimental-agent-team/lib/types/session-message.d.ts +11 -0
- package/dist/kernel/experimental-agent-team/lib/types/session-message.js +23 -0
- package/dist/kernel/experimental-agent-team/lib/types/task-board.d.ts +62 -0
- package/dist/kernel/experimental-agent-team/lib/types/task-board.js +275 -0
- package/dist/kernel/experimental-agent-team/lib/types/task-graph.d.ts +21 -0
- package/dist/kernel/experimental-agent-team/lib/types/task-graph.js +62 -0
- package/dist/kernel/experimental-agent-team/lib/types/types.d.ts +192 -0
- package/dist/kernel/experimental-agent-team/lib/types/types.js +26 -0
- package/dist/kernel/experimental-agent-team/lib/types/validation.d.ts +16 -0
- package/dist/kernel/experimental-agent-team/lib/types/validation.js +33 -0
- package/dist/kernel/experimental-agent-team/package.json +62 -0
- package/dist/kernel/experimental-tool-agent-team/lib/index.js +555 -0
- package/dist/kernel/experimental-tool-agent-team/lib/invariant.js +13 -0
- package/dist/kernel/experimental-tool-agent-team/lib/types/index.d.ts +19 -0
- package/dist/kernel/experimental-tool-agent-team/lib/types/index.js +379 -0
- package/dist/kernel/experimental-tool-agent-team/lib/types/invariant.d.ts +9 -0
- package/dist/kernel/experimental-tool-agent-team/lib/types/invariant.js +11 -0
- package/dist/kernel/experimental-tool-agent-team/package.json +61 -0
- package/dist/kernel/file-reference/lib/index.js +138 -0
- package/dist/kernel/file-reference/lib/invariant.js +23 -0
- package/dist/kernel/file-reference/lib/typert.host.d.ts +3 -0
- package/dist/kernel/file-reference/lib/typert.host.js +436 -0
- package/dist/kernel/file-reference/lib/typert.remote-client.d.ts +26 -0
- package/dist/kernel/file-reference/lib/typert.remote-client.js +59 -0
- package/dist/kernel/file-reference/lib/types/grammar.d.ts +33 -0
- package/dist/kernel/file-reference/lib/types/grammar.js +43 -0
- package/dist/kernel/file-reference/lib/types/index.d.ts +42 -0
- package/dist/kernel/file-reference/lib/types/index.js +75 -0
- package/dist/kernel/file-reference/lib/types/invariant.d.ts +16 -0
- package/dist/kernel/file-reference/lib/types/invariant.js +22 -0
- package/dist/kernel/file-reference/lib/types/types.d.ts +13 -0
- package/dist/kernel/file-reference/lib/types/types.js +7 -0
- package/dist/kernel/file-reference/package.json +70 -0
- package/dist/kernel/file-reference-local/lib/index.js +327 -0
- package/dist/kernel/file-reference-local/lib/invariant.js +23 -0
- package/dist/kernel/file-reference-local/lib/types/index.d.ts +35 -0
- package/dist/kernel/file-reference-local/lib/types/index.js +105 -0
- package/dist/kernel/file-reference-local/lib/types/invariant.d.ts +16 -0
- package/dist/kernel/file-reference-local/lib/types/invariant.js +22 -0
- package/dist/kernel/file-reference-local/lib/types/search.d.ts +52 -0
- package/dist/kernel/file-reference-local/lib/types/search.js +258 -0
- package/dist/kernel/file-reference-local/package.json +58 -0
- package/dist/kernel/fs/package.json +1 -1
- package/dist/kernel/fs-e2b/package.json +1 -1
- package/dist/kernel/fs-local/package.json +1 -1
- package/dist/kernel/fs-observation-policy/package.json +1 -1
- package/dist/kernel/fs-sandbox/package.json +1 -1
- package/dist/kernel/goal/lib/index.js +5 -2
- package/dist/kernel/goal/lib/typert.host.js +27 -3
- package/dist/kernel/goal/lib/types/index.js +2 -2
- package/dist/kernel/goal/lib/types/types.d.ts +3 -0
- package/dist/kernel/goal/package.json +1 -1
- package/dist/kernel/goal-round-driver/package.json +1 -1
- package/dist/kernel/headless/package.json +1 -1
- package/dist/kernel/home-paths/package.json +1 -1
- package/dist/kernel/hook-protocol/package.json +1 -1
- package/dist/kernel/hooks-claude-code/package.json +1 -1
- package/dist/kernel/hooks-codex/package.json +1 -1
- package/dist/kernel/host-apiproxy/lib/index.js +25 -57
- package/dist/kernel/host-apiproxy/lib/types/api/host.d.ts +2 -0
- package/dist/kernel/host-apiproxy/lib/types/api/host.schema.d.ts +1 -0
- package/dist/kernel/host-apiproxy/lib/types/api/host.schema.js +1 -0
- package/dist/kernel/host-apiproxy/lib/types/api/sessions.d.ts +4 -0
- package/dist/kernel/host-apiproxy/lib/types/api/sessions.schema.js +1 -0
- package/dist/kernel/host-apiproxy/lib/types/api-proxy.js +15 -53
- package/dist/kernel/host-apiproxy/package.json +1 -1
- package/dist/kernel/host-directory-picker/package.json +1 -1
- package/dist/kernel/host-directory-picker-auto/package.json +1 -1
- package/dist/kernel/host-directory-picker-browse/package.json +1 -1
- package/dist/kernel/host-directory-picker-native/package.json +1 -1
- package/dist/kernel/host-frontend-static/lib/index.js +34 -26
- package/dist/kernel/host-frontend-static/lib/types/index.d.ts +10 -10
- package/dist/kernel/host-frontend-static/lib/types/index.js +38 -27
- package/dist/kernel/host-frontend-static/package.json +2 -2
- package/dist/kernel/host-plugin-inventory/package.json +1 -1
- package/dist/kernel/host-webserver/lib/index.js +102 -6
- package/dist/kernel/host-webserver/lib/types/index.d.ts +33 -5
- package/dist/kernel/host-webserver/lib/types/index.js +28 -5
- package/dist/kernel/host-webserver/lib/types/injections.d.ts +56 -0
- package/dist/kernel/host-webserver/lib/types/injections.js +82 -0
- package/dist/kernel/host-webserver/package.json +1 -1
- package/dist/kernel/invariants/package.json +1 -1
- package/dist/kernel/jobs/package.json +1 -1
- package/dist/kernel/jobs-local/package.json +1 -1
- package/dist/kernel/launch-environment/package.json +1 -1
- package/dist/kernel/llm/lib/index.js +247 -25
- package/dist/kernel/llm/lib/types/assembler.d.ts +10 -1
- package/dist/kernel/llm/lib/types/assembler.js +20 -1
- package/dist/kernel/llm/lib/types/content.d.ts +59 -0
- package/dist/kernel/llm/lib/types/content.js +149 -0
- package/dist/kernel/llm/lib/types/index.d.ts +24 -1
- package/dist/kernel/llm/lib/types/index.js +61 -8
- package/dist/kernel/llm/lib/types/retry-policy.d.ts +1 -1
- package/dist/kernel/llm/lib/types/retry-policy.js +6 -2
- package/dist/kernel/llm/package.json +1 -1
- package/dist/kernel/llm-deepseek/lib/index.js +1100 -70
- package/dist/kernel/llm-deepseek/lib/types/adapter.d.ts +69 -1
- package/dist/kernel/llm-deepseek/lib/types/adapter.js +296 -60
- package/dist/kernel/llm-deepseek/lib/types/file-id.d.ts +19 -0
- package/dist/kernel/llm-deepseek/lib/types/file-id.js +18 -0
- package/dist/kernel/llm-deepseek/lib/types/file-store.d.ts +83 -0
- package/dist/kernel/llm-deepseek/lib/types/file-store.js +261 -0
- package/dist/kernel/llm-deepseek/lib/types/files-api.d.ts +103 -0
- package/dist/kernel/llm-deepseek/lib/types/files-api.js +206 -0
- package/dist/kernel/llm-deepseek/lib/types/index.d.ts +31 -3
- package/dist/kernel/llm-deepseek/lib/types/index.js +139 -3
- package/dist/kernel/llm-deepseek/lib/types/serialize.d.ts +55 -6
- package/dist/kernel/llm-deepseek/lib/types/serialize.js +179 -23
- package/dist/kernel/llm-deepseek/lib/types/types.d.ts +28 -5
- package/dist/kernel/llm-deepseek/lib/types/upload-index.d.ts +68 -0
- package/dist/kernel/llm-deepseek/lib/types/upload-index.js +171 -0
- package/dist/kernel/llm-deepseek/package.json +9 -1
- package/dist/kernel/llm-pi-ai/lib/index.js +1758 -1171
- package/dist/kernel/llm-pi-ai/lib/types/adapter.d.ts +30 -5
- package/dist/kernel/llm-pi-ai/lib/types/adapter.js +43 -23
- package/dist/kernel/llm-pi-ai/lib/types/auth.d.ts +60 -0
- package/dist/kernel/llm-pi-ai/lib/types/auth.js +196 -0
- package/dist/kernel/llm-pi-ai/lib/types/catalog.d.ts +176 -38
- package/dist/kernel/llm-pi-ai/lib/types/catalog.js +245 -50
- package/dist/kernel/llm-pi-ai/lib/types/config.d.ts +37 -5
- package/dist/kernel/llm-pi-ai/lib/types/config.js +67 -2
- package/dist/kernel/llm-pi-ai/lib/types/context.d.ts +8 -3
- package/dist/kernel/llm-pi-ai/lib/types/context.js +60 -16
- package/dist/kernel/llm-pi-ai/lib/types/index.d.ts +1 -0
- package/dist/kernel/llm-pi-ai/lib/types/index.js +21 -19
- package/dist/kernel/llm-pi-ai/lib/types/login.d.ts +21 -0
- package/dist/kernel/llm-pi-ai/lib/types/login.js +154 -0
- package/dist/kernel/llm-pi-ai/lib/types/stream.js +4 -0
- package/dist/kernel/llm-pi-ai/package.json +3 -1
- package/dist/kernel/llm-retry/package.json +1 -1
- package/dist/kernel/lsp/package.json +1 -1
- package/dist/kernel/lsp-stdio/package.json +1 -1
- package/dist/kernel/manifest.json +10 -2
- package/dist/kernel/mcp-client/package.json +1 -1
- package/dist/kernel/message-feedback/package.json +1 -1
- package/dist/kernel/native-command/package.json +1 -1
- package/dist/kernel/node-addon-landlock-run/lib/index.js +1 -1
- package/dist/kernel/node-addon-landlock-run/package.json +4 -2
- package/dist/kernel/output-retention/package.json +1 -1
- package/dist/kernel/permission-presets/lib/index.js +14 -2
- package/dist/kernel/permission-presets/lib/types/index.d.ts +5 -0
- package/dist/kernel/permission-presets/lib/types/index.js +11 -2
- package/dist/kernel/permission-presets/package.json +1 -1
- package/dist/kernel/persona/package.json +1 -1
- package/dist/kernel/plan-mode/lib/index.js +49 -15
- package/dist/kernel/plan-mode/lib/types/index.d.ts +22 -0
- package/dist/kernel/plan-mode/lib/types/index.js +45 -19
- package/dist/kernel/plan-mode/lib/types/types.d.ts +5 -4
- package/dist/kernel/plan-mode/package.json +1 -1
- package/dist/kernel/pwsh-local/package.json +1 -1
- package/dist/kernel/pwsh-sandbox/package.json +1 -1
- package/dist/kernel/repeat-tool-reminder/lib/index.js +1 -1
- package/dist/kernel/repeat-tool-reminder/package.json +1 -1
- package/dist/kernel/sandbox/package.json +1 -1
- package/dist/kernel/sandbox-local/lib/index.js +8 -13
- package/dist/kernel/sandbox-local/lib/types/index.d.ts +1 -3
- package/dist/kernel/sandbox-local/lib/types/index.js +4 -7
- package/dist/kernel/sandbox-local/lib/types/profiles.js +1 -1
- package/dist/kernel/sandbox-local/package.json +1 -1
- package/dist/kernel/sandbox-policy/package.json +1 -1
- package/dist/kernel/sandbox-windows-acl/package.json +1 -1
- package/dist/kernel/schedule/package.json +1 -1
- package/dist/kernel/schemastery/package.json +3 -1
- package/dist/kernel/scope/package.json +1 -1
- package/dist/kernel/sdk-client/lib/index.js +2 -2
- package/dist/kernel/sdk-client/lib/types/api.js +2 -2
- package/dist/kernel/sdk-client/lib/types/types.d.ts +4 -4
- package/dist/kernel/sdk-client/package.json +1 -1
- package/dist/kernel/sdk-jsonrpc-server/lib/index.js +12 -5
- package/dist/kernel/sdk-jsonrpc-server/lib/types/index.js +7 -0
- package/dist/kernel/sdk-jsonrpc-server/lib/types/server.d.ts +2 -1
- package/dist/kernel/sdk-jsonrpc-server/lib/types/server.js +15 -6
- package/dist/kernel/sdk-jsonrpc-server/package.json +2 -1
- package/dist/kernel/sdk-protocol/package.json +1 -1
- package/dist/kernel/session/lib/index.js +4 -0
- package/dist/kernel/session/lib/types/known-event-types.js +4 -0
- package/dist/kernel/session/lib/types/types.d.ts +6 -1
- package/dist/kernel/session/package.json +1 -1
- package/dist/kernel/session-checkpoint-policy/package.json +1 -1
- package/dist/kernel/session-log-export/package.json +2 -5
- package/dist/kernel/session-persistence/lib/index.js +1 -1
- package/dist/kernel/session-persistence/lib/types/coordinator.js +2 -1
- package/dist/kernel/session-persistence/package.json +1 -1
- package/dist/kernel/session-persistence-jsonl/package.json +1 -1
- package/dist/kernel/session-persistence-sqlite/lib/index.js +1105 -375
- package/dist/kernel/session-persistence-sqlite/lib/invariant.js +2 -2
- package/dist/kernel/session-persistence-sqlite/lib/types/codec.d.ts +72 -0
- package/dist/kernel/session-persistence-sqlite/lib/types/codec.js +304 -0
- package/dist/kernel/session-persistence-sqlite/lib/types/compression.d.ts +46 -0
- package/dist/kernel/session-persistence-sqlite/lib/types/compression.js +234 -0
- package/dist/kernel/session-persistence-sqlite/lib/types/index.d.ts +22 -80
- package/dist/kernel/session-persistence-sqlite/lib/types/index.js +27 -278
- package/dist/kernel/session-persistence-sqlite/lib/types/invariant.js +2 -2
- package/dist/kernel/session-persistence-sqlite/lib/types/schema.d.ts +63 -85
- package/dist/kernel/session-persistence-sqlite/lib/types/schema.js +293 -159
- package/dist/kernel/session-persistence-sqlite/lib/types/sql.d.ts +15 -0
- package/dist/kernel/session-persistence-sqlite/lib/types/sql.js +57 -0
- package/dist/kernel/session-persistence-sqlite/lib/types/store.d.ts +66 -0
- package/dist/kernel/session-persistence-sqlite/lib/types/store.js +394 -0
- package/dist/kernel/session-persistence-sqlite/package.json +9 -3
- package/dist/kernel/session-persistence-sqlite/resources/sql/begin-immediate.sql +1 -0
- package/dist/kernel/session-persistence-sqlite/resources/sql/begin.sql +1 -0
- package/dist/kernel/session-persistence-sqlite/resources/sql/commit.sql +1 -0
- package/dist/kernel/session-persistence-sqlite/resources/sql/delete-events-from.sql +2 -0
- package/dist/kernel/session-persistence-sqlite/resources/sql/foreign-keys-on.sql +1 -0
- package/dist/kernel/session-persistence-sqlite/resources/sql/insert-event.sql +3 -0
- package/dist/kernel/session-persistence-sqlite/resources/sql/insert-persistence-state.sql +2 -0
- package/dist/kernel/session-persistence-sqlite/resources/sql/journal-mode-delete.sql +1 -0
- package/dist/kernel/session-persistence-sqlite/resources/sql/journal-mode-persist.sql +1 -0
- package/dist/kernel/session-persistence-sqlite/resources/sql/journal-mode-truncate.sql +1 -0
- package/dist/kernel/session-persistence-sqlite/resources/sql/journal-mode-wal.sql +1 -0
- package/dist/kernel/session-persistence-sqlite/resources/sql/mmap-off.sql +1 -0
- package/dist/kernel/session-persistence-sqlite/resources/sql/rollback.sql +1 -0
- package/dist/kernel/session-persistence-sqlite/resources/sql/schema.sql +30 -0
- package/dist/kernel/session-persistence-sqlite/resources/sql/select-application-id.sql +1 -0
- package/dist/kernel/session-persistence-sqlite/resources/sql/select-events-from.sql +4 -0
- package/dist/kernel/session-persistence-sqlite/resources/sql/select-events.sql +4 -0
- package/dist/kernel/session-persistence-sqlite/resources/sql/select-mmap-size.sql +1 -0
- package/dist/kernel/session-persistence-sqlite/resources/sql/select-packed-predecessors.sql +6 -0
- package/dist/kernel/session-persistence-sqlite/resources/sql/select-schema-objects.sql +4 -0
- package/dist/kernel/session-persistence-sqlite/resources/sql/select-session.sql +4 -0
- package/dist/kernel/session-persistence-sqlite/resources/sql/select-sessions.sql +3 -0
- package/dist/kernel/session-persistence-sqlite/resources/sql/select-store-id.sql +3 -0
- package/dist/kernel/session-persistence-sqlite/resources/sql/select-synchronous.sql +1 -0
- package/dist/kernel/session-persistence-sqlite/resources/sql/select-tail-events.sql +5 -0
- package/dist/kernel/session-persistence-sqlite/resources/sql/select-trusted-schema.sql +1 -0
- package/dist/kernel/session-persistence-sqlite/resources/sql/select-user-object-count.sql +3 -0
- package/dist/kernel/session-persistence-sqlite/resources/sql/select-user-version.sql +1 -0
- package/dist/kernel/session-persistence-sqlite/resources/sql/set-application-id.sql +1 -0
- package/dist/kernel/session-persistence-sqlite/resources/sql/set-user-version-17.sql +1 -0
- package/dist/kernel/session-persistence-sqlite/resources/sql/synchronous-full.sql +1 -0
- package/dist/kernel/session-persistence-sqlite/resources/sql/trusted-schema-off.sql +1 -0
- package/dist/kernel/session-persistence-sqlite/resources/sql/update-session-revision.sql +3 -0
- package/dist/kernel/session-persistence-sqlite/resources/sql/upsert-session.sql +13 -0
- package/dist/kernel/session-projection/lib/index.js +55 -30
- package/dist/kernel/session-projection/lib/types/index.d.ts +57 -34
- package/dist/kernel/session-projection/lib/types/index.js +61 -36
- package/dist/kernel/session-projection/lib/types/types.d.ts +11 -4
- package/dist/kernel/session-projection/package.json +1 -1
- package/dist/kernel/session-projection-cache/lib/index.js +1 -1
- package/dist/kernel/session-projection-cache/lib/types/index.d.ts +1 -1
- package/dist/kernel/session-projection-cache/lib/types/index.js +4 -5
- package/dist/kernel/session-projection-cache/package.json +1 -1
- package/dist/kernel/session-query/package.json +1 -1
- package/dist/kernel/session-query-sqlite/package.json +1 -1
- package/dist/kernel/session-reference/lib/index.js +232 -110
- package/dist/kernel/session-reference/lib/typert.host.d.ts +3 -0
- package/dist/kernel/session-reference/lib/typert.host.js +458 -0
- package/dist/kernel/session-reference/lib/typert.remote-client.d.ts +26 -0
- package/dist/kernel/session-reference/lib/typert.remote-client.js +62 -0
- package/dist/kernel/session-reference/lib/types/index.d.ts +25 -5
- package/dist/kernel/session-reference/lib/types/index.js +230 -126
- package/dist/kernel/session-reference/lib/types/types.d.ts +14 -3
- package/dist/kernel/session-reference/lib/types/types.js +6 -1
- package/dist/kernel/session-reference/package.json +23 -3
- package/dist/kernel/session-stats/lib/index.js +31 -12
- package/dist/kernel/session-stats/lib/types/projection.d.ts +64 -2
- package/dist/kernel/session-stats/lib/types/projection.js +31 -12
- package/dist/kernel/session-stats/package.json +1 -1
- package/dist/kernel/session-telemetry/package.json +1 -1
- package/dist/kernel/session-telemetry-otel/package.json +1 -1
- package/dist/kernel/session-title/lib/index.js +6 -2
- package/dist/kernel/session-title/lib/types/index.js +3 -2
- package/dist/kernel/session-title/lib/types/types.d.ts +3 -0
- package/dist/kernel/session-title/package.json +1 -1
- package/dist/kernel/session-title-all-prompts-llm/package.json +1 -1
- package/dist/kernel/session-title-first-prompt-llm/package.json +1 -1
- package/dist/kernel/session-title-llm/package.json +1 -1
- package/dist/kernel/settings/package.json +1 -1
- package/dist/kernel/settings-file/package.json +1 -1
- package/dist/kernel/shell/package.json +1 -1
- package/dist/kernel/shell-env/package.json +1 -1
- package/dist/kernel/skill/package.json +1 -1
- package/dist/kernel/skill-badge/assets/nomix-badge.md +6 -6
- package/dist/kernel/skill-badge/assets/nomix-badge.png +0 -0
- package/dist/kernel/skill-badge/lib/index.js +1 -1
- package/dist/kernel/skill-badge/lib/types/index.js +1 -1
- package/dist/kernel/skill-badge/package.json +1 -1
- package/dist/kernel/skill-filesystem/package.json +1 -1
- package/dist/kernel/spill/package.json +1 -1
- package/dist/kernel/spill-local/package.json +1 -1
- package/dist/kernel/spill-policy/package.json +1 -1
- package/dist/kernel/storage/package.json +1 -1
- package/dist/kernel/storage-domain/package.json +1 -1
- package/dist/kernel/storage-json/package.json +1 -1
- package/dist/kernel/storage-sqlite/package.json +1 -1
- package/dist/kernel/subagent/lib/index.js +123 -20
- package/dist/kernel/subagent/lib/types/continuation.d.ts +21 -2
- package/dist/kernel/subagent/lib/types/continuation.js +58 -7
- package/dist/kernel/subagent/lib/types/index.d.ts +11 -0
- package/dist/kernel/subagent/lib/types/index.js +16 -0
- package/dist/kernel/subagent/lib/types/out-of-process.d.ts +2 -0
- package/dist/kernel/subagent/lib/types/out-of-process.js +31 -1
- package/dist/kernel/subagent/lib/types/projection.d.ts +55 -8
- package/dist/kernel/subagent/lib/types/projection.js +30 -15
- package/dist/kernel/subagent/lib/types/run-settlement.js +10 -3
- package/dist/kernel/subagent/lib/types/types.d.ts +7 -0
- package/dist/kernel/subagent/package.json +1 -1
- package/dist/kernel/subagent-acp/package.json +1 -1
- package/dist/kernel/subagent-claude-code/cordis.patch.yml +6 -0
- package/dist/kernel/subagent-claude-code/lib/index.js +267 -73
- package/dist/kernel/subagent-claude-code/lib/types/index.d.ts +16 -6
- package/dist/kernel/subagent-claude-code/lib/types/index.js +35 -14
- package/dist/kernel/subagent-claude-code/lib/types/process.d.ts +5 -7
- package/dist/kernel/subagent-claude-code/lib/types/process.js +12 -24
- package/dist/kernel/subagent-claude-code/lib/types/run.d.ts +24 -7
- package/dist/kernel/subagent-claude-code/lib/types/run.js +266 -40
- package/dist/kernel/subagent-claude-code/package.json +10 -2
- package/dist/kernel/subagent-codex/cordis.patch.yml +5 -0
- package/dist/kernel/subagent-codex/lib/index.js +482 -91
- package/dist/kernel/subagent-codex/lib/types/index.d.ts +11 -6
- package/dist/kernel/subagent-codex/lib/types/index.js +33 -12
- package/dist/kernel/subagent-codex/lib/types/run.d.ts +17 -8
- package/dist/kernel/subagent-codex/lib/types/run.js +235 -42
- package/dist/kernel/subagent-codex/lib/types/wire.d.ts +49 -1
- package/dist/kernel/subagent-codex/lib/types/wire.js +280 -33
- package/dist/kernel/subagent-codex/package.json +10 -5
- package/dist/kernel/subagent-fork-in-process/package.json +1 -1
- package/dist/kernel/subagent-in-process-driver/package.json +1 -1
- package/dist/kernel/subagent-nomix-sdk/package.json +1 -1
- package/dist/kernel/subagent-spawn-in-process/package.json +1 -1
- package/dist/kernel/subprocess/package.json +1 -1
- package/dist/kernel/subprocess-e2b/package.json +1 -1
- package/dist/kernel/subprocess-local/lib/index.js +303 -1
- package/dist/kernel/subprocess-local/lib/types/process-inspector.js +3 -0
- package/dist/kernel/subprocess-local/lib/types/terminal.d.ts +6 -1
- package/dist/kernel/subprocess-local/lib/types/terminal.js +78 -1
- package/dist/kernel/subprocess-local/lib/types/windows-inspector.d.ts +80 -0
- package/dist/kernel/subprocess-local/lib/types/windows-inspector.js +259 -0
- package/dist/kernel/subprocess-local/package.json +2 -1
- package/dist/kernel/system-prompt/package.json +1 -1
- package/dist/kernel/terminal/package.json +1 -1
- package/dist/kernel/terminal-bash/lib/index.js +85 -20
- package/dist/kernel/terminal-bash/lib/types/config.d.ts +29 -5
- package/dist/kernel/terminal-bash/lib/types/config.js +33 -3
- package/dist/kernel/terminal-bash/lib/types/index.d.ts +7 -0
- package/dist/kernel/terminal-bash/lib/types/index.js +65 -13
- package/dist/kernel/terminal-bash/package.json +2 -1
- package/dist/kernel/time-context/lib/index.js +1 -1
- package/dist/kernel/time-context/lib/invariant.js +1 -1
- package/dist/kernel/time-context/package.json +1 -1
- package/dist/kernel/timeout/package.json +1 -1
- package/dist/kernel/tmux-context/lib/index.js +1 -1
- package/dist/kernel/tmux-context/package.json +1 -1
- package/dist/kernel/token-meter/lib/index.js +77 -21
- package/dist/kernel/token-meter/lib/types/breakdown-projection.d.ts +76 -9
- package/dist/kernel/token-meter/lib/types/breakdown-projection.js +22 -6
- package/dist/kernel/token-meter/lib/types/usage-projection.d.ts +186 -25
- package/dist/kernel/token-meter/lib/types/usage-projection.js +44 -15
- package/dist/kernel/token-meter/package.json +1 -1
- package/dist/kernel/tool-ask-user/package.json +1 -1
- package/dist/kernel/tool-bash/package.json +1 -1
- package/dist/kernel/tool-bash-persistent/lib/index.js +15 -5
- package/dist/kernel/tool-bash-persistent/lib/types/index.js +23 -6
- package/dist/kernel/tool-bash-persistent/package.json +1 -1
- package/dist/kernel/tool-call-timeout-policy/package.json +1 -1
- package/dist/kernel/tool-cordis/lib/index.js +655 -83
- package/dist/kernel/tool-cordis/lib/types/api-catalog.js +439 -41
- package/dist/kernel/tool-cordis/package.json +1 -1
- package/dist/kernel/tool-fs/lib/index.js +80 -52
- package/dist/kernel/tool-fs/lib/types/read-image.d.ts +16 -12
- package/dist/kernel/tool-fs/lib/types/read-image.js +73 -29
- package/dist/kernel/tool-fs/package.json +1 -1
- package/dist/kernel/tool-fs-search/lib/index.js +11 -7
- package/dist/kernel/tool-fs-search/lib/types/search-core.d.ts +5 -6
- package/dist/kernel/tool-fs-search/lib/types/search-core.js +12 -7
- package/dist/kernel/tool-fs-search/package.json +1 -1
- package/dist/kernel/tool-goal/package.json +1 -1
- package/dist/kernel/tool-jobs/package.json +1 -1
- package/dist/kernel/tool-lsp/package.json +1 -1
- package/dist/kernel/tool-pwsh/package.json +1 -1
- package/dist/kernel/tool-pwsh-persistent/lib/index.js +407 -0
- package/dist/kernel/tool-pwsh-persistent/lib/invariant.js +24 -0
- package/dist/kernel/tool-pwsh-persistent/lib/types/index.d.ts +24 -0
- package/dist/kernel/tool-pwsh-persistent/lib/types/index.js +465 -0
- package/dist/kernel/tool-pwsh-persistent/lib/types/invariant.d.ts +16 -0
- package/dist/kernel/tool-pwsh-persistent/lib/types/invariant.js +23 -0
- package/dist/kernel/tool-pwsh-persistent/package.json +62 -0
- package/dist/kernel/tool-ralph/package.json +1 -1
- package/dist/kernel/tool-session-query/package.json +1 -1
- package/dist/kernel/tool-skill/package.json +1 -1
- package/dist/kernel/tool-str-replace-editor/package.json +1 -1
- package/dist/kernel/tool-subagent/lib/index.js +10 -8
- package/dist/kernel/tool-subagent/lib/types/index.js +15 -8
- package/dist/kernel/tool-subagent/package.json +1 -1
- package/dist/kernel/tool-subagent-control/package.json +1 -1
- package/dist/kernel/tool-subagent-report/lib/index.js +1 -1
- package/dist/kernel/tool-subagent-report/lib/types/index.d.ts +3 -3
- package/dist/kernel/tool-subagent-report/lib/types/index.js +1 -1
- package/dist/kernel/tool-subagent-report/package.json +1 -1
- package/dist/kernel/tool-terminal/package.json +1 -1
- package/dist/kernel/tool-todo/lib/index.js +5 -2
- package/dist/kernel/tool-todo/lib/types/index.js +2 -2
- package/dist/kernel/tool-todo/lib/types/types.d.ts +3 -0
- package/dist/kernel/tool-todo/package.json +1 -1
- package/dist/kernel/tool-web/lib/index.js +101 -26
- package/dist/kernel/tool-web/lib/types/index.d.ts +4 -2
- package/dist/kernel/tool-web/lib/types/index.js +5 -3
- package/dist/kernel/tool-web/lib/types/search.d.ts +23 -20
- package/dist/kernel/tool-web/lib/types/search.js +109 -20
- package/dist/kernel/tool-web/package.json +1 -1
- package/dist/kernel/tool-workflow/package.json +1 -1
- package/dist/kernel/tools/package.json +1 -1
- package/dist/kernel/typert-generator/lib/index.js +8 -3
- package/dist/kernel/typert-generator/lib/types/cordis-catalog.js +8 -3
- package/dist/kernel/typert-generator/package.json +1 -1
- package/dist/kernel/typert-loader/package.json +1 -1
- package/dist/kernel/typert-protocol/package.json +1 -1
- package/dist/kernel/typert-registry/package.json +1 -1
- package/dist/kernel/user-approval/package.json +1 -1
- package/dist/kernel/user-questions/package.json +1 -1
- package/dist/kernel/web/lib/types/types.d.ts +4 -3
- package/dist/kernel/web/package.json +1 -1
- package/dist/kernel/web-app/cordis.patch.yml +27 -6
- package/dist/kernel/web-app/lib/index.js +111 -15
- package/dist/kernel/web-app/lib/startup.js +4 -2
- package/dist/kernel/web-app/lib/types/index.d.ts +8 -4
- package/dist/kernel/web-app/lib/types/index.js +116 -23
- package/dist/kernel/web-app/lib/types/startup.d.ts +3 -1
- package/dist/kernel/web-app/lib/types/startup.js +4 -1
- package/dist/kernel/web-app/package.json +12 -2
- package/dist/kernel/web-fetch-http/lib/index.js +1 -1
- package/dist/kernel/web-fetch-http/lib/types/index.d.ts +1 -1
- package/dist/kernel/web-fetch-http/lib/types/index.js +1 -1
- package/dist/kernel/web-fetch-http/package.json +1 -1
- package/dist/kernel/web-frontend/dist/assets/index-BnapMmQ_.css +1 -0
- package/dist/kernel/web-frontend/dist/assets/index-Dx7Ws_OC.js +96 -0
- package/dist/kernel/web-frontend/dist/assets/langs/{php-D-uCvoST.js → php-DDkx9sim.js} +2 -2
- package/dist/{assets/web/assets/langs/ruby-DEItuUFs.js → kernel/web-frontend/dist/assets/langs/ruby-DCxyoPen.js} +2 -2
- package/dist/kernel/web-frontend/dist/assets/{vendor-Cjbwl5VI.js → vendor-D22_Mp1f.js} +2 -2
- package/dist/kernel/web-frontend/dist/favicon.svg +8 -0
- package/dist/kernel/web-frontend/dist/index.html +5 -5
- package/dist/kernel/web-frontend/package.json +5 -8
- package/dist/kernel/web-search-deepseek/lib/index.js +1 -1
- package/dist/kernel/web-search-deepseek/lib/types/provider.js +1 -1
- package/dist/kernel/web-search-deepseek/package.json +1 -1
- package/dist/kernel/web-search-exa/lib/index.js +1 -1
- package/dist/kernel/web-search-exa/lib/types/provider.js +1 -1
- package/dist/kernel/web-search-exa/package.json +1 -1
- package/dist/kernel/web-search-perplexity/lib/index.js +1 -1
- package/dist/kernel/web-search-perplexity/lib/types/provider.js +1 -1
- package/dist/kernel/web-search-perplexity/package.json +1 -1
- package/dist/kernel/workflow/package.json +1 -1
- package/dist/kernel/workflow-worker-thread/package.json +1 -1
- package/dist/kernel/workspace/package.json +1 -1
- package/dist/plugins/manifest.json +50 -10
- package/dist/runtime/index.js +0 -2
- package/package.json +8 -6
- package/dist/assets/web/assets/index-B_fSXASy.css +0 -1
- package/dist/assets/web/assets/index-B_sZ-Gsu.js +0 -112
- package/dist/cli/builtin-registry.d.ts +0 -5
- package/dist/cli/profile-boot-CeU09iFc.js +0 -2
- package/dist/kernel/app-boot/lib/types/legacy-branding.d.ts +0 -6
- package/dist/kernel/app-boot/lib/types/legacy-branding.js +0 -18
- package/dist/kernel/client-schema-form/lib/index.js +0 -137
- package/dist/kernel/client-schema-form/lib/types/index.d.ts +0 -10
- package/dist/kernel/client-schema-form/lib/types/index.js +0 -9
- package/dist/kernel/client-schema-form/lib/types/model.d.ts +0 -66
- package/dist/kernel/client-schema-form/lib/types/model.js +0 -153
- package/dist/kernel/client-ui-subagent/lib/types/client/SubagentCatalogAction.d.ts +0 -18
- package/dist/kernel/client-ui-theme/lib/styles/base.css +0 -15
- package/dist/kernel/client-ui-theme/lib/styles/design-platform.css +0 -338
- package/dist/kernel/client-ui-theme/lib/styles/gradient-shadow-text.css +0 -232
- package/dist/kernel/client-ui-theme/lib/styles/scrollbar.css +0 -90
- package/dist/kernel/client-ui-theme/lib/styles/shiki.css +0 -31
- package/dist/kernel/client-web/lib/types/AppRoot.d.ts +0 -16
- package/dist/kernel/client-web/lib/types/AppRoot.js +0 -27
- package/dist/kernel/client-web/lib/types/DocumentTitle.js +0 -16
- package/dist/kernel/client-web/lib/types/app-shell.d.ts +0 -28
- package/dist/kernel/client-web/lib/types/app-shell.js +0 -27
- package/dist/kernel/client-web/lib/types/app.d.ts +0 -21
- package/dist/kernel/client-web-react/lib/index.js +0 -810
- package/dist/kernel/client-web-react/lib/types/index.d.ts +0 -16
- package/dist/kernel/client-web-react/lib/types/index.js +0 -6
- package/dist/kernel/client-web-react/lib/types/use-invoke.d.ts +0 -9
- package/dist/kernel/client-web-react/lib/types/use-invoke.js +0 -52
- package/dist/kernel/skill-badge/assets/nomix-badge.svg +0 -8
- package/dist/kernel/web-frontend/dist/assets/index-B_fSXASy.css +0 -1
- package/dist/kernel/web-frontend/dist/assets/index-B_sZ-Gsu.js +0 -112
- /package/dist/kernel/{client-web-react/lib/types → client-ui-renderer/lib/types/client}/bind.js +0 -0
- /package/dist/kernel/{client-web-react/lib/types → client-ui-renderer/lib/types/client}/session-provider.js +0 -0
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { launchEnvironmentOf } from "../../launch-environment/lib/index.js";
|
|
2
|
-
import { CONTEXT_WINDOW_EXCEEDED_CODE, CallId, EMPTY_RESPONSE_CODE, INVALID_CREDENTIAL_CODE, LlmAdapter, LlmError, QUOTA_EXCEEDED_CODE, ReasoningEffortId, RetryPolicySchema, assertUsableApiKey, attributionHeaders, contentHasImage, isContextWindowExceededError, isQuotaExceededError, normalizeApiKey, resolveRetryPolicy } from "../../llm/lib/index.js";
|
|
2
|
+
import { CONTEXT_WINDOW_EXCEEDED_CODE, CallId, EMPTY_RESPONSE_CODE, INVALID_CREDENTIAL_CODE, LlmAdapter, LlmError, QUOTA_EXCEEDED_CODE, ReasoningEffortId, RetryPolicySchema, assertUsableApiKey, attributionHeaders, contentHasImage, isContextWindowExceededError, isQuotaExceededError, normalizeApiKey, offloadRequestImagesWithPolicy, requestImageHandleText, resolveRetryPolicy } from "../../llm/lib/index.js";
|
|
3
3
|
import { deepEqualJson, installSettingsSection, settingsNamespace } from "../../settings/lib/index.js";
|
|
4
4
|
import { createModels, createProvider, getSupportedThinkingLevels, isContextOverflow } from "@earendil-works/pi-ai";
|
|
5
5
|
import { MAX_TIMER_DELAY_MS, idleWatchdog, timeoutOf } from "../../timeout/lib/index.js";
|
|
6
|
-
import { builtinProviders, getBuiltinModels, getBuiltinProviders } from "@earendil-works/pi-ai/providers/all";
|
|
7
6
|
import z from "../../schemastery/lib/index.mjs";
|
|
8
|
-
import { credentialRef } from "../../credentials/lib/index.js";
|
|
7
|
+
import { credentialKey, credentialKeyId, credentialKeyScope, credentialRef, isCredentialKeySegment, isCredentialRefName } from "../../credentials/lib/index.js";
|
|
8
|
+
import { builtinProviders, getBuiltinModels, getBuiltinProviders } from "@earendil-works/pi-ai/providers/all";
|
|
9
9
|
import { anthropicMessagesApi } from "@earendil-works/pi-ai/api/anthropic-messages.lazy";
|
|
10
10
|
import { openAICompletionsApi } from "@earendil-works/pi-ai/api/openai-completions.lazy";
|
|
11
11
|
import { openAIResponsesApi } from "@earendil-works/pi-ai/api/openai-responses.lazy";
|
|
12
|
+
import { homedir } from "node:os";
|
|
13
|
+
import { access } from "node:fs/promises";
|
|
14
|
+
import { resolve } from "node:path";
|
|
12
15
|
//#region lib/types/replay.js
|
|
13
16
|
/**
|
|
14
17
|
* Durable pi-ai replay metadata and assistant-history reconstruction.
|
|
@@ -241,1269 +244,1700 @@ function toPiAssistant(message, onDegrade) {
|
|
|
241
244
|
}
|
|
242
245
|
}
|
|
243
246
|
//#endregion
|
|
244
|
-
//#region lib/types/
|
|
247
|
+
//#region lib/types/catalog.js
|
|
245
248
|
/**
|
|
246
|
-
*
|
|
249
|
+
* Materialization of one provider route's model catalog. The installed pi-ai
|
|
250
|
+
* catalog supplies defaults keyed by model id, and a profile's own model
|
|
251
|
+
* entries override them field by field, so a route naming a catalog provider
|
|
252
|
+
* stays configuration-free while a route pi-ai has never heard of is fully
|
|
253
|
+
* describable from `settings.yaml`.
|
|
247
254
|
*
|
|
248
|
-
*
|
|
255
|
+
* Every pi-ai `Model` field the harness cannot default is required here rather
|
|
256
|
+
* than at request time: an unserviceable route fails while its configuration is
|
|
257
|
+
* being resolved, which is the earliest point that can name the offending key.
|
|
258
|
+
*
|
|
259
|
+
* @module nomix-llm-pi-ai/catalog
|
|
249
260
|
*/
|
|
250
|
-
/**
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
{
|
|
278
|
-
const nested = await userContent(block.content, attachments);
|
|
279
|
-
if (typeof nested === "string") {
|
|
280
|
-
if (nested.length > 0) content.push({
|
|
281
|
-
type: "text",
|
|
282
|
-
text: nested
|
|
283
|
-
});
|
|
284
|
-
} else content.push(...nested);
|
|
285
|
-
}
|
|
286
|
-
break;
|
|
287
|
-
default: break;
|
|
288
|
-
}
|
|
289
|
-
if (content.every((block) => block.type === "text")) return content.map((block) => block.text).join("");
|
|
290
|
-
return content;
|
|
291
|
-
}
|
|
292
|
-
function toolsOf(options) {
|
|
293
|
-
return options.tools?.map((tool) => ({
|
|
294
|
-
name: tool.name,
|
|
295
|
-
description: tool.description,
|
|
296
|
-
parameters: tool.parameters
|
|
297
|
-
}));
|
|
261
|
+
/**
|
|
262
|
+
* Pricing for a model the installed catalog does not describe. The harness
|
|
263
|
+
* never reads pi-ai's cost metadata — `replay.ts` zeroes it and no consumer
|
|
264
|
+
* reports spend — so this is the absence of a fact, not a configurable rate.
|
|
265
|
+
*/
|
|
266
|
+
const NO_COST = {
|
|
267
|
+
input: 0,
|
|
268
|
+
output: 0,
|
|
269
|
+
cacheRead: 0,
|
|
270
|
+
cacheWrite: 0
|
|
271
|
+
};
|
|
272
|
+
/** Every request modality a profile may declare. */
|
|
273
|
+
const MODALITIES = Object.keys({
|
|
274
|
+
text: true,
|
|
275
|
+
image: true
|
|
276
|
+
});
|
|
277
|
+
/**
|
|
278
|
+
* One entry's modality list, or `undefined` when it states no answer. Absent
|
|
279
|
+
* and empty mean the same thing — `[]` describes a model that accepts nothing
|
|
280
|
+
* and could serve no request — which is what makes an entry naming a catalog
|
|
281
|
+
* model without declaring modalities keep the catalog's, since the config
|
|
282
|
+
* schema materializes `[]` for an absent array.
|
|
283
|
+
* @param configured - the list a `models` or `modelOverrides` entry supplied.
|
|
284
|
+
* @returns the declared modalities, or `undefined` to ask the next level.
|
|
285
|
+
*/
|
|
286
|
+
function declaredInput(configured) {
|
|
287
|
+
return configured === void 0 || configured.length === 0 ? void 0 : [...configured];
|
|
298
288
|
}
|
|
299
|
-
/**
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
289
|
+
/** Every pi-ai thinking level a profile may declare, in escalation order. */
|
|
290
|
+
const THINKING_LEVELS = Object.keys({
|
|
291
|
+
off: true,
|
|
292
|
+
minimal: true,
|
|
293
|
+
low: true,
|
|
294
|
+
medium: true,
|
|
295
|
+
high: true,
|
|
296
|
+
xhigh: true,
|
|
297
|
+
max: true
|
|
298
|
+
});
|
|
299
|
+
/** Reasoning-dispatch wire formats a profile may name, most-reached first. */
|
|
300
|
+
const SUPPORTED_THINKING_FORMATS = Object.keys({
|
|
301
|
+
"openai": true,
|
|
302
|
+
"deepseek": true,
|
|
303
|
+
"openrouter": true,
|
|
304
|
+
"together": true,
|
|
305
|
+
"zai": true,
|
|
306
|
+
"qwen": true,
|
|
307
|
+
"chat-template": true,
|
|
308
|
+
"qwen-chat-template": true,
|
|
309
|
+
"string-thinking": true,
|
|
310
|
+
"ant-ling": true
|
|
311
|
+
});
|
|
312
|
+
/** The output-cap field spellings a profile may name. */
|
|
313
|
+
const MAX_TOKENS_FIELDS = Object.keys({
|
|
314
|
+
max_completion_tokens: true,
|
|
315
|
+
max_tokens: true
|
|
316
|
+
});
|
|
317
|
+
/** The prompt-cache marker conventions a profile may name. */
|
|
318
|
+
const CACHE_CONTROL_FORMATS = Object.keys({ anthropic: true });
|
|
319
|
+
/** The request-state placeholders a profile may name. */
|
|
320
|
+
const CHAT_TEMPLATE_VARS = Object.keys({
|
|
321
|
+
"thinking.enabled": true,
|
|
322
|
+
"thinking.effort": true
|
|
323
|
+
});
|
|
324
|
+
let providerIndex;
|
|
325
|
+
/**
|
|
326
|
+
* Installed catalog providers by id, constructed once. Each entry owns the API
|
|
327
|
+
* implementations for its own models, which is why a catalog route reuses this
|
|
328
|
+
* provider instead of being rebuilt from parts.
|
|
329
|
+
* @returns the catalog provider index.
|
|
330
|
+
*/
|
|
331
|
+
function catalogProviders() {
|
|
332
|
+
providerIndex ??= new Map(builtinProviders().map((provider) => [provider.id, provider]));
|
|
333
|
+
return providerIndex;
|
|
307
334
|
}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
role: "user",
|
|
316
|
-
content: flattenText(message),
|
|
317
|
-
timestamp: 0
|
|
318
|
-
});
|
|
319
|
-
continue;
|
|
320
|
-
}
|
|
321
|
-
if (message.role === "assistant") {
|
|
322
|
-
const assistant = toPiAssistant(message, onReplayDegrade);
|
|
323
|
-
for (const block of assistant.content) if (block.type === "toolCall") toolNames.set(CallId(block.id), block.name);
|
|
324
|
-
messages.push(assistant);
|
|
325
|
-
continue;
|
|
326
|
-
}
|
|
327
|
-
const text = flattenText(message);
|
|
328
|
-
const results = message.content.filter((block) => block.type === "tool-result");
|
|
329
|
-
if (text.length > 0 || results.length === 0) messages.push({
|
|
330
|
-
role: "user",
|
|
331
|
-
content: text,
|
|
332
|
-
timestamp: 0
|
|
333
|
-
});
|
|
334
|
-
for (const result of results) messages.push({
|
|
335
|
-
role: "toolResult",
|
|
336
|
-
toolCallId: result.toolCallId,
|
|
337
|
-
toolName: toolNames.get(result.toolCallId) ?? "unknown",
|
|
338
|
-
content: [{
|
|
339
|
-
type: "text",
|
|
340
|
-
text: toolResultText(result.content) || "(no output)"
|
|
341
|
-
}],
|
|
342
|
-
isError: result.isError ?? false,
|
|
343
|
-
timestamp: 0
|
|
344
|
-
});
|
|
345
|
-
}
|
|
346
|
-
return piContext(options, messages);
|
|
335
|
+
/**
|
|
336
|
+
* The installed catalog provider for one route, when pi-ai ships one.
|
|
337
|
+
* @param provider - provider route key.
|
|
338
|
+
* @returns the catalog provider, or `undefined` for a route pi-ai does not ship.
|
|
339
|
+
*/
|
|
340
|
+
function catalogProvider(provider) {
|
|
341
|
+
return catalogProviders().get(provider);
|
|
347
342
|
}
|
|
348
|
-
|
|
349
|
-
|
|
343
|
+
/**
|
|
344
|
+
* Every provider route the installed pi-ai catalog ships.
|
|
345
|
+
* @returns the catalog provider ids.
|
|
346
|
+
*/
|
|
347
|
+
function catalogProviderIds() {
|
|
348
|
+
return getBuiltinProviders();
|
|
350
349
|
}
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
timestamp: 0
|
|
361
|
-
});
|
|
362
|
-
continue;
|
|
363
|
-
}
|
|
364
|
-
if (message.role === "assistant") {
|
|
365
|
-
const assistant = toPiAssistant(message, onReplayDegrade);
|
|
366
|
-
for (const block of assistant.content) if (block.type === "toolCall") toolNames.set(CallId(block.id), block.name);
|
|
367
|
-
messages.push(assistant);
|
|
368
|
-
continue;
|
|
369
|
-
}
|
|
370
|
-
const content = await userContent(message.content.filter((block) => block.type !== "tool-result"), attachments);
|
|
371
|
-
const results = message.content.filter((block) => block.type === "tool-result");
|
|
372
|
-
if (content.length > 0 || results.length === 0) messages.push({
|
|
373
|
-
role: "user",
|
|
374
|
-
content,
|
|
375
|
-
timestamp: 0
|
|
376
|
-
});
|
|
377
|
-
for (const result of results) {
|
|
378
|
-
const resultContent = await userContent(result.content, attachments);
|
|
379
|
-
messages.push({
|
|
380
|
-
role: "toolResult",
|
|
381
|
-
toolCallId: result.toolCallId,
|
|
382
|
-
toolName: toolNames.get(result.toolCallId) ?? "unknown",
|
|
383
|
-
content: typeof resultContent === "string" ? [{
|
|
384
|
-
type: "text",
|
|
385
|
-
text: resultContent || "(no output)"
|
|
386
|
-
}] : resultContent,
|
|
387
|
-
isError: result.isError ?? false,
|
|
388
|
-
timestamp: 0
|
|
389
|
-
});
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
return piContext(options, messages);
|
|
350
|
+
/**
|
|
351
|
+
* The installed catalog models for one route, indexed by model id.
|
|
352
|
+
* @param provider - provider route key.
|
|
353
|
+
* @returns catalog models by id; empty for a route pi-ai does not ship.
|
|
354
|
+
*/
|
|
355
|
+
function catalogModels(provider) {
|
|
356
|
+
if (!catalogProviders().has(provider)) return /* @__PURE__ */ new Map();
|
|
357
|
+
const models = getBuiltinModels(provider);
|
|
358
|
+
return new Map(models.map((model) => [model.id, model]));
|
|
393
359
|
}
|
|
394
|
-
//#endregion
|
|
395
|
-
//#region lib/types/stream.js
|
|
396
360
|
/**
|
|
397
|
-
*
|
|
361
|
+
* Disposition of every `OpenAICompletionsCompat` field. The `Record` key type
|
|
362
|
+
* is a drift gate: a pi-ai upgrade that adds a field fails compilation here
|
|
363
|
+
* until it is classified, so the offer never silently lags the upstream set.
|
|
364
|
+
*/
|
|
365
|
+
const COMPLETIONS_COMPAT_GATE = {
|
|
366
|
+
supportsStore: "offer",
|
|
367
|
+
supportsDeveloperRole: "offer",
|
|
368
|
+
supportsReasoningEffort: "offer",
|
|
369
|
+
supportsUsageInStreaming: "offer",
|
|
370
|
+
maxTokensField: "offer",
|
|
371
|
+
requiresToolResultName: "offer",
|
|
372
|
+
requiresAssistantAfterToolResult: "offer",
|
|
373
|
+
requiresThinkingAsText: "offer",
|
|
374
|
+
requiresReasoningContentOnAssistantMessages: "offer",
|
|
375
|
+
thinkingFormat: "offer",
|
|
376
|
+
chatTemplateKwargs: "offer",
|
|
377
|
+
supportsStrictMode: "offer",
|
|
378
|
+
cacheControlFormat: "offer",
|
|
379
|
+
supportsLongCacheRetention: "offer",
|
|
380
|
+
openRouterRouting: "withhold",
|
|
381
|
+
vercelGatewayRouting: "withhold",
|
|
382
|
+
zaiToolStream: "withhold",
|
|
383
|
+
supportsOpenAIGrammarTools: "withhold",
|
|
384
|
+
sendSessionAffinityHeaders: "withhold",
|
|
385
|
+
deferredToolsMode: "withhold",
|
|
386
|
+
sessionAffinityFormat: "withhold"
|
|
387
|
+
};
|
|
388
|
+
/** Disposition of every `OpenAIResponsesCompat` field; a drift gate like the one above. */
|
|
389
|
+
const RESPONSES_COMPAT_GATE = {
|
|
390
|
+
supportsDeveloperRole: "offer",
|
|
391
|
+
supportsStrictMode: "offer",
|
|
392
|
+
supportsLongCacheRetention: "offer",
|
|
393
|
+
sessionAffinityFormat: "withhold",
|
|
394
|
+
supportsOpenAIGrammarTools: "withhold",
|
|
395
|
+
supportsToolSearch: "withhold",
|
|
396
|
+
supportsExplicitPromptCacheMode: "withhold"
|
|
397
|
+
};
|
|
398
|
+
/**
|
|
399
|
+
* The compat gate of every wire protocol a profile may configure.
|
|
398
400
|
*
|
|
399
|
-
*
|
|
400
|
-
*
|
|
401
|
-
*
|
|
401
|
+
* Keyed by protocol, but grouped by pi-ai's compat *type*: the three Responses
|
|
402
|
+
* protocols share `OpenAIResponsesCompat`, so a switch settable on one is
|
|
403
|
+
* settable on all three. Keying by protocol alone would refuse
|
|
404
|
+
* `azure-openai-responses` and `openai-codex-responses` the fields their own
|
|
405
|
+
* models declare.
|
|
406
|
+
*/
|
|
407
|
+
const COMPAT_GATES = {
|
|
408
|
+
"openai-completions": COMPLETIONS_COMPAT_GATE,
|
|
409
|
+
"openai-responses": RESPONSES_COMPAT_GATE,
|
|
410
|
+
"azure-openai-responses": RESPONSES_COMPAT_GATE,
|
|
411
|
+
"openai-codex-responses": RESPONSES_COMPAT_GATE,
|
|
412
|
+
"anthropic-messages": {
|
|
413
|
+
supportsEagerToolInputStreaming: "offer",
|
|
414
|
+
supportsLongCacheRetention: "offer",
|
|
415
|
+
supportsCacheControlOnTools: "offer",
|
|
416
|
+
supportsTemperature: "offer",
|
|
417
|
+
forceAdaptiveThinking: "offer",
|
|
418
|
+
allowEmptySignature: "offer",
|
|
419
|
+
supportsStrictTools: "offer",
|
|
420
|
+
sendSessionAffinityHeaders: "withhold",
|
|
421
|
+
supportsToolReferences: "withhold"
|
|
422
|
+
},
|
|
423
|
+
"bedrock-converse-stream": { supportsStrictMode: "offer" }
|
|
424
|
+
};
|
|
425
|
+
/**
|
|
426
|
+
* The compat gate of one resolved protocol. A `string` lookup rather than a
|
|
427
|
+
* keyed read: a route's `api` is configuration, so it may name a protocol
|
|
428
|
+
* pi-ai gives no compat type — or none at all.
|
|
429
|
+
* @param api - resolved wire protocol.
|
|
430
|
+
* @returns that protocol's field gate, or `undefined` when it takes no compat.
|
|
431
|
+
*/
|
|
432
|
+
function compatGate(api) {
|
|
433
|
+
return COMPAT_GATES[api];
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* The compat entries a profile actually set.
|
|
402
437
|
*
|
|
403
|
-
*
|
|
438
|
+
* schemastery materializes an absent dict as `{}` — the behavior
|
|
439
|
+
* `reasoningEfforts` works around with a union — so every parsed profile
|
|
440
|
+
* carries a `chatTemplateKwargs` key whether or not anyone wrote one. An empty
|
|
441
|
+
* one states nothing here: it would send no kwargs, which is exactly what
|
|
442
|
+
* leaving the field out does, so absent and empty are the same request and
|
|
443
|
+
* neither may make a route look like it configured a switch. A valueless
|
|
444
|
+
* scalar is the other thing schemastery lets through, and it is refused by
|
|
445
|
+
* {@link assertOfferedCompatFields} before this runs rather than filtered.
|
|
446
|
+
* @param compat - the configured switches, when any.
|
|
447
|
+
* @returns the entries carrying a value, in declaration order.
|
|
404
448
|
*/
|
|
449
|
+
function configuredCompatEntries(compat) {
|
|
450
|
+
return Object.entries(compat ?? {}).flatMap(([field, value]) => {
|
|
451
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && Object.keys(value).length === 0 ? [] : [[field, value]];
|
|
452
|
+
});
|
|
453
|
+
}
|
|
405
454
|
/**
|
|
406
|
-
*
|
|
407
|
-
* @param
|
|
408
|
-
* @returns
|
|
455
|
+
* The protocols offering one compat field, in {@link COMPAT_GATES} order.
|
|
456
|
+
* @param field - configured compat field name.
|
|
457
|
+
* @returns the protocols whose compat takes it; empty when none does, which
|
|
458
|
+
* is either a withheld field or a name no upstream compat type declares.
|
|
409
459
|
*/
|
|
410
|
-
function
|
|
411
|
-
return
|
|
412
|
-
inputTokens: usage.input,
|
|
413
|
-
outputTokens: usage.output,
|
|
414
|
-
...usage.cacheRead > 0 ? { cacheReadTokens: usage.cacheRead } : {},
|
|
415
|
-
...usage.cacheWrite > 0 ? { cacheWriteTokens: usage.cacheWrite } : {}
|
|
416
|
-
};
|
|
460
|
+
function compatProtocols(field) {
|
|
461
|
+
return Object.entries(COMPAT_GATES).flatMap(([api, gate]) => gate[field] === "offer" ? [api] : []);
|
|
417
462
|
}
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
if (/\b(?:network|connection|socket|fetch)\b|\bECONN[A-Z]+\b/i.test(message) || /\b(?:other side closed|HTTP2 request did not get a response|WebSocket closed unexpectedly)\b/i.test(message) || /\bterminated\b|premature close/i.test(message)) return "TRANSPORT";
|
|
427
|
-
return "PI_AI_ERROR";
|
|
463
|
+
/**
|
|
464
|
+
* The compat fields one protocol offers, for a diagnostic that has to show
|
|
465
|
+
* what was available instead of the name that missed.
|
|
466
|
+
* @param api - wire protocol.
|
|
467
|
+
* @returns the offered field names, or an empty list for a protocol taking no compat.
|
|
468
|
+
*/
|
|
469
|
+
function offeredCompatFields(api) {
|
|
470
|
+
return Object.entries(compatGate(api) ?? {}).flatMap(([field, disposition]) => disposition === "offer" ? [field] : []);
|
|
428
471
|
}
|
|
429
472
|
/**
|
|
430
|
-
*
|
|
431
|
-
*
|
|
432
|
-
*
|
|
433
|
-
*
|
|
434
|
-
*
|
|
435
|
-
* to `CONTEXT_WINDOW_EXCEEDED`; a `stop` with no content blocks maps to an
|
|
436
|
-
* `EMPTY_RESPONSE` error.
|
|
473
|
+
* Every offered field name, deduplicated, for the one diagnostic that cannot
|
|
474
|
+
* narrow by protocol: the vocabulary check runs before any protocol resolves,
|
|
475
|
+
* which is what lets it refuse a misspelling on a route whose models would
|
|
476
|
+
* never have reached the protocol that declares the intended field.
|
|
477
|
+
* @returns the offered field names across every protocol, in gate order.
|
|
437
478
|
*/
|
|
438
|
-
function
|
|
439
|
-
const
|
|
440
|
-
const
|
|
441
|
-
|
|
442
|
-
kind: "error",
|
|
443
|
-
failure: {
|
|
444
|
-
message: message.errorMessage ?? `pi-ai detected context overflow for model "${message.model}"`,
|
|
445
|
-
code: CONTEXT_WINDOW_EXCEEDED_CODE
|
|
446
|
-
}
|
|
447
|
-
};
|
|
448
|
-
switch (message.stopReason) {
|
|
449
|
-
case "stop":
|
|
450
|
-
if (message.content.length === 0) return {
|
|
451
|
-
kind: "error",
|
|
452
|
-
failure: {
|
|
453
|
-
message: `model "${message.model}" returned a completed response with no content`,
|
|
454
|
-
code: EMPTY_RESPONSE_CODE
|
|
455
|
-
}
|
|
456
|
-
};
|
|
457
|
-
return { kind: "stop" };
|
|
458
|
-
case "length": return { kind: "max-tokens" };
|
|
459
|
-
case "toolUse": return { kind: "tool-calls" };
|
|
460
|
-
case "aborted": return {
|
|
461
|
-
kind: "aborted",
|
|
462
|
-
failure: {
|
|
463
|
-
message: message.errorMessage ?? "pi-ai stream aborted",
|
|
464
|
-
code: "ABORTED"
|
|
465
|
-
}
|
|
466
|
-
};
|
|
467
|
-
case "error": {
|
|
468
|
-
const text = message.errorMessage ?? "pi-ai stream error";
|
|
469
|
-
return {
|
|
470
|
-
kind: "error",
|
|
471
|
-
failure: {
|
|
472
|
-
message: text,
|
|
473
|
-
code: classifyPiAiError(text)
|
|
474
|
-
}
|
|
475
|
-
};
|
|
476
|
-
}
|
|
477
|
-
}
|
|
479
|
+
function allOfferedCompatFields() {
|
|
480
|
+
const fields = /* @__PURE__ */ new Set();
|
|
481
|
+
for (const api of Object.keys(COMPAT_GATES)) for (const field of offeredCompatFields(api)) fields.add(field);
|
|
482
|
+
return [...fields];
|
|
478
483
|
}
|
|
479
484
|
/**
|
|
480
|
-
*
|
|
481
|
-
*
|
|
482
|
-
*
|
|
483
|
-
*
|
|
484
|
-
* @param
|
|
485
|
-
* @
|
|
486
|
-
*
|
|
485
|
+
* Reject a compat key no protocol offers. Runs before any protocol is
|
|
486
|
+
* resolved, so a withheld field or a misspelling fails even on a route whose
|
|
487
|
+
* models never reach the protocol that would have taken it — the alternative
|
|
488
|
+
* being the silent drop that let an unreadable switch look applied.
|
|
489
|
+
* @param provider - provider route key, for diagnostics.
|
|
490
|
+
* @param site - the configuration site, for diagnostics.
|
|
491
|
+
* @param compat - the configured switches, when any.
|
|
492
|
+
* @throws Error naming the offending key.
|
|
487
493
|
*/
|
|
488
|
-
|
|
489
|
-
const
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
yield {
|
|
494
|
-
type: "block-start",
|
|
495
|
-
index: event.contentIndex,
|
|
496
|
-
blockType: "text"
|
|
497
|
-
};
|
|
498
|
-
break;
|
|
499
|
-
case "text_delta":
|
|
500
|
-
yield {
|
|
501
|
-
type: "text-delta",
|
|
502
|
-
index: event.contentIndex,
|
|
503
|
-
text: event.delta
|
|
504
|
-
};
|
|
505
|
-
break;
|
|
506
|
-
case "text_end":
|
|
507
|
-
yield {
|
|
508
|
-
type: "block-end",
|
|
509
|
-
index: event.contentIndex,
|
|
510
|
-
block: {
|
|
511
|
-
type: "text",
|
|
512
|
-
text: event.content
|
|
513
|
-
}
|
|
514
|
-
};
|
|
515
|
-
break;
|
|
516
|
-
case "thinking_start":
|
|
517
|
-
yield {
|
|
518
|
-
type: "block-start",
|
|
519
|
-
index: event.contentIndex,
|
|
520
|
-
blockType: "reasoning"
|
|
521
|
-
};
|
|
522
|
-
break;
|
|
523
|
-
case "thinking_delta":
|
|
524
|
-
yield {
|
|
525
|
-
type: "reasoning-delta",
|
|
526
|
-
index: event.contentIndex,
|
|
527
|
-
text: event.delta
|
|
528
|
-
};
|
|
529
|
-
break;
|
|
530
|
-
case "thinking_end":
|
|
531
|
-
yield {
|
|
532
|
-
type: "block-end",
|
|
533
|
-
index: event.contentIndex,
|
|
534
|
-
block: {
|
|
535
|
-
type: "reasoning",
|
|
536
|
-
text: event.content
|
|
537
|
-
}
|
|
538
|
-
};
|
|
539
|
-
break;
|
|
540
|
-
case "toolcall_start": {
|
|
541
|
-
const partial = event.partial.content[event.contentIndex];
|
|
542
|
-
const id = partial?.type === "toolCall" ? partial.id : "";
|
|
543
|
-
const name = partial?.type === "toolCall" ? partial.name : "";
|
|
544
|
-
toolIds.set(event.contentIndex, {
|
|
545
|
-
id,
|
|
546
|
-
name
|
|
547
|
-
});
|
|
548
|
-
yield {
|
|
549
|
-
type: "block-start",
|
|
550
|
-
index: event.contentIndex,
|
|
551
|
-
blockType: "tool-call"
|
|
552
|
-
};
|
|
553
|
-
break;
|
|
554
|
-
}
|
|
555
|
-
case "toolcall_delta": {
|
|
556
|
-
const known = toolIds.get(event.contentIndex);
|
|
557
|
-
yield {
|
|
558
|
-
type: "tool-call-delta",
|
|
559
|
-
index: event.contentIndex,
|
|
560
|
-
id: CallId(known?.id ?? ""),
|
|
561
|
-
...known?.name !== void 0 && known.name.length > 0 ? { name: known.name } : {},
|
|
562
|
-
argumentsDelta: event.delta
|
|
563
|
-
};
|
|
564
|
-
break;
|
|
494
|
+
function assertOfferedCompatFields(provider, site, compat) {
|
|
495
|
+
for (const [field, value] of Object.entries(compat ?? {})) {
|
|
496
|
+
if (compatProtocols(field).length === 0) {
|
|
497
|
+
if (Object.values(COMPAT_GATES).some((gate) => gate[field] !== void 0)) invalid(provider, `${site} sets compat "${field}", which is not configurable here: pi-ai's installed catalog sets it for the vendors that need it, so name that provider as the route instead`);
|
|
498
|
+
invalid(provider, `${site} sets compat "${field}", which no wire protocol declares; the configurable switches are ${allOfferedCompatFields().join(", ")}`);
|
|
565
499
|
}
|
|
566
|
-
|
|
567
|
-
yield {
|
|
568
|
-
type: "block-end",
|
|
569
|
-
index: event.contentIndex,
|
|
570
|
-
block: {
|
|
571
|
-
type: "tool-call",
|
|
572
|
-
id: CallId(event.toolCall.id),
|
|
573
|
-
name: event.toolCall.name,
|
|
574
|
-
arguments: JSON.stringify(event.toolCall.arguments)
|
|
575
|
-
}
|
|
576
|
-
};
|
|
577
|
-
break;
|
|
578
|
-
case "done":
|
|
579
|
-
yield {
|
|
580
|
-
type: "usage",
|
|
581
|
-
usage: mapUsage(event.message.usage)
|
|
582
|
-
};
|
|
583
|
-
yield {
|
|
584
|
-
type: "finish",
|
|
585
|
-
reason: mapStopReason(event.message, contextWindow),
|
|
586
|
-
replayState: toPiReplayState(event.message)
|
|
587
|
-
};
|
|
588
|
-
return;
|
|
589
|
-
case "error":
|
|
590
|
-
yield {
|
|
591
|
-
type: "usage",
|
|
592
|
-
usage: mapUsage(event.error.usage)
|
|
593
|
-
};
|
|
594
|
-
yield {
|
|
595
|
-
type: "finish",
|
|
596
|
-
reason: mapStopReason(event.error, contextWindow)
|
|
597
|
-
};
|
|
598
|
-
return;
|
|
500
|
+
if (value == null) invalid(provider, `${site} sets compat "${field}" with no value; give it one, or remove the key to leave the field to the next layer — the installed catalog entry, then pi-ai's own detection`);
|
|
599
501
|
}
|
|
600
|
-
throw new LlmError("pi-ai event stream ended without done/error", "STREAM_CLOSED");
|
|
601
502
|
}
|
|
602
|
-
|
|
603
|
-
|
|
503
|
+
/** Report a route the deployment cannot serve, naming the settings key at fault. */
|
|
504
|
+
function invalid(provider, detail) {
|
|
505
|
+
throw new Error(`llm-pi-ai: provider "${provider}" ${detail}`);
|
|
506
|
+
}
|
|
604
507
|
/**
|
|
605
|
-
*
|
|
606
|
-
*
|
|
607
|
-
*
|
|
608
|
-
*
|
|
609
|
-
*
|
|
610
|
-
*
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
508
|
+
* The one wire protocol a catalog route's shipped models agree on. This is what
|
|
509
|
+
* lets a deployment add a model the installed catalog has not caught up with —
|
|
510
|
+
* a provider's newest release — without restating the protocol its siblings
|
|
511
|
+
* already use. A route whose shipped models disagree (an OpenAI-style catalog
|
|
512
|
+
* spanning Responses and Chat Completions) has no such answer, so a model it
|
|
513
|
+
* does not describe must name its protocol at the route.
|
|
514
|
+
*/
|
|
515
|
+
function sharedCatalogApi(defaults) {
|
|
516
|
+
const apis = /* @__PURE__ */ new Set();
|
|
517
|
+
for (const model of defaults.values()) apis.add(model.api);
|
|
518
|
+
return apis.size === 1 ? [...apis][0] : void 0;
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* Resolve one model's reasoning capability from its declared efforts.
|
|
618
522
|
*
|
|
619
|
-
*
|
|
620
|
-
*
|
|
621
|
-
*
|
|
622
|
-
*
|
|
523
|
+
* A declared dict translates to pi-ai's `thinkingLevelMap` with every level
|
|
524
|
+
* decided explicitly: declared levels carry their wire spelling, undeclared
|
|
525
|
+
* levels are pinned to `null` (unsupported). Pinning matters because pi-ai's
|
|
526
|
+
* own defaulting is asymmetric — an absent key means "supported" for the five
|
|
527
|
+
* base levels but "unsupported" for `xhigh`/`max` — and a profile author
|
|
528
|
+
* should not need to know that. A declared `off` with no value is the one
|
|
529
|
+
* exception: it stays absent from the map, which pi-ai reads as "supported,
|
|
530
|
+
* send nothing" — the correct dispatch where not thinking is the parameter's
|
|
531
|
+
* absence — while `off` with a value sends that value.
|
|
532
|
+
* @param provider - provider route key, for diagnostics.
|
|
533
|
+
* @param entry - the configured model entry.
|
|
534
|
+
* @param base - the installed catalog entry of the same id, when one exists.
|
|
535
|
+
* @returns the reasoning fields the materialized model carries.
|
|
536
|
+
*/
|
|
537
|
+
function resolveModelReasoning(provider, entry, base) {
|
|
538
|
+
const efforts = entry.reasoningEfforts;
|
|
539
|
+
if (efforts === void 0) return { reasoning: base?.reasoning ?? false };
|
|
540
|
+
if (efforts === false) return { reasoning: false };
|
|
541
|
+
if (efforts === null || Object.keys(efforts).length === 0) invalid(provider, `model "${entry.id}" has an empty reasoningEfforts; declare the offered levels, set false for a non-reasoning model, or omit the field to keep the installed catalog's capability`);
|
|
542
|
+
const declared = THINKING_LEVELS.flatMap((level) => {
|
|
543
|
+
const wire = efforts[level];
|
|
544
|
+
return wire === void 0 ? [] : [[level, wire]];
|
|
545
|
+
});
|
|
546
|
+
for (const [level, wire] of declared) if (wire === null) {
|
|
547
|
+
if (level !== "off") invalid(provider, `model "${entry.id}" reasoningEfforts.${level} needs the wire value dispatch should send; only "off" may leave it empty`);
|
|
548
|
+
} else if (wire.length === 0) invalid(provider, `model "${entry.id}" reasoningEfforts.${level} must not be an empty string`);
|
|
549
|
+
if (!declared.some(([level]) => level !== "off")) invalid(provider, `model "${entry.id}" reasoningEfforts offers no level beyond "off"; declare a thinking level, or set reasoningEfforts to false for a non-reasoning model`);
|
|
550
|
+
const map = {};
|
|
551
|
+
for (const level of THINKING_LEVELS) {
|
|
552
|
+
const wire = efforts[level];
|
|
553
|
+
if (wire === void 0) map[level] = null;
|
|
554
|
+
else if (wire !== null) map[level] = wire;
|
|
555
|
+
}
|
|
556
|
+
return {
|
|
557
|
+
reasoning: true,
|
|
558
|
+
thinkingLevelMap: map
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* Resolve one model's compat block from the profile's switches.
|
|
623
563
|
*
|
|
624
|
-
*
|
|
564
|
+
* A model switch wins over the route switch field by field; whatever neither
|
|
565
|
+
* sets keeps the installed entry's value, and a field no layer decides falls
|
|
566
|
+
* through to pi-ai's own detection. A model-level switch its protocol does not
|
|
567
|
+
* take fails resolution — about one named model it can only be a mistake —
|
|
568
|
+
* while a route-level one skips past such models, since a route default must
|
|
569
|
+
* stay settable on a route whose models do not all speak one protocol. Every
|
|
570
|
+
* field reaching here is offered by some protocol; {@link
|
|
571
|
+
* assertOfferedCompatFields} has already refused the rest.
|
|
572
|
+
* @param provider - provider route key, for diagnostics.
|
|
573
|
+
* @param entry - the configured model entry.
|
|
574
|
+
* @param route - the route-level switches, when any.
|
|
575
|
+
* @param base - the installed catalog entry of the same id, when one exists.
|
|
576
|
+
* @param api - the model's resolved wire protocol.
|
|
577
|
+
* @returns a `compat` field to spread into the model, or nothing.
|
|
625
578
|
*/
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
if (
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
if (
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
if (async) inner = dispose;
|
|
579
|
+
function resolveModelCompat(provider, entry, route, base, api) {
|
|
580
|
+
const gate = compatGate(api);
|
|
581
|
+
const configured = {};
|
|
582
|
+
for (const [field, value] of configuredCompatEntries(route)) {
|
|
583
|
+
if (gate?.[field] !== "offer") continue;
|
|
584
|
+
configured[field] = value;
|
|
585
|
+
}
|
|
586
|
+
for (const [field, value] of configuredCompatEntries(entry.compat)) {
|
|
587
|
+
if (gate?.[field] !== "offer") {
|
|
588
|
+
const offered = offeredCompatFields(api);
|
|
589
|
+
invalid(provider, `model "${entry.id}" sets compat "${field}", but its api is "${api}", which does not take it; that switch exists on ${compatProtocols(field).join(", ")}, and "${api}" offers ${offered.length === 0 ? "no configurable compat" : offered.join(", ")}`);
|
|
638
590
|
}
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
591
|
+
configured[field] = value;
|
|
592
|
+
}
|
|
593
|
+
if (Object.keys(configured).length === 0) return {};
|
|
594
|
+
return { compat: {
|
|
595
|
+
...base?.api === api ? base.compat : void 0,
|
|
596
|
+
...configured
|
|
597
|
+
} };
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* Materialize one route's catalog by merging the installed catalog defaults
|
|
601
|
+
* under the configured entries. A route with no configured `models` serves the
|
|
602
|
+
* installed catalog unchanged, which is what keeps an existing
|
|
603
|
+
* `providers: { deepseek: { apiKeyEnv: … } }` profile working untouched.
|
|
604
|
+
* @param request - the route-level catalog facts.
|
|
605
|
+
* @returns the materialized models and the explicitly configured request caps.
|
|
606
|
+
*/
|
|
607
|
+
function resolveRouteModels(request) {
|
|
608
|
+
const { provider } = request;
|
|
609
|
+
const defaults = catalogModels(provider);
|
|
610
|
+
const providerBaseUrl = catalogProvider(provider)?.baseUrl;
|
|
611
|
+
const configured = request.models ?? [];
|
|
612
|
+
const overrides = request.modelOverrides ?? {};
|
|
613
|
+
for (const [id, override] of Object.entries(overrides)) {
|
|
614
|
+
if (id.length === 0) invalid(provider, "has a modelOverrides entry with an empty model id");
|
|
615
|
+
if (defaults.size === 0) invalid(provider, `sets modelOverrides for "${id}", but the installed catalog does not describe this route; a declared route spells every model out in its models list`);
|
|
616
|
+
if (configured.length > 0) invalid(provider, `sets modelOverrides for "${id}" beside a models list; models already replaces the served catalog, so declare the fields on its entries`);
|
|
617
|
+
if (!defaults.has(id)) invalid(provider, `modelOverrides names "${id}", which the installed catalog does not describe`);
|
|
618
|
+
if ("id" in override) invalid(provider, `modelOverrides entry "${id}" sets "id", which is the dict key`);
|
|
619
|
+
}
|
|
620
|
+
const entries = configured.length > 0 ? configured : [...defaults.values()].map((model) => ({
|
|
621
|
+
id: model.id,
|
|
622
|
+
...overrides[model.id]
|
|
623
|
+
}));
|
|
624
|
+
if (entries.length === 0) invalid(provider, "resolves no models; the installed catalog does not describe this route, so its models must be listed in configuration");
|
|
625
|
+
const routeApi = sharedCatalogApi(defaults);
|
|
626
|
+
assertOfferedCompatFields(provider, "route", request.compat);
|
|
627
|
+
for (const entry of entries) assertOfferedCompatFields(provider, `model "${entry.id}"`, entry.compat);
|
|
628
|
+
const seen = /* @__PURE__ */ new Set();
|
|
629
|
+
const configuredMaxTokens = /* @__PURE__ */ new Map();
|
|
630
|
+
const models = entries.map((entry) => {
|
|
631
|
+
if (entry.id.length === 0) invalid(provider, "has a model with an empty id");
|
|
632
|
+
if (seen.has(entry.id)) invalid(provider, `lists model "${entry.id}" more than once`);
|
|
633
|
+
seen.add(entry.id);
|
|
634
|
+
const base = defaults.get(entry.id);
|
|
635
|
+
const api = request.api ?? base?.api ?? routeApi;
|
|
636
|
+
if (api === void 0) invalid(provider, `model "${entry.id}" needs an api; the installed catalog does not describe it, so set the route's api to the wire protocol its endpoint speaks`);
|
|
637
|
+
const baseUrl = request.baseURL ?? base?.baseUrl ?? providerBaseUrl;
|
|
638
|
+
if (baseUrl === void 0) invalid(provider, `model "${entry.id}" needs a baseURL; the installed catalog does not describe this route`);
|
|
639
|
+
const contextWindow = entry.contextWindow ?? base?.contextWindow ?? request.defaultContextWindow;
|
|
640
|
+
if (!Number.isInteger(contextWindow) || contextWindow <= 0) invalid(provider, `model "${entry.id}" contextWindow must be a positive integer`);
|
|
641
|
+
const maxTokens = entry.maxTokens ?? base?.maxTokens ?? request.defaultMaxTokens;
|
|
642
|
+
if (!Number.isInteger(maxTokens) || maxTokens <= 0) invalid(provider, `model "${entry.id}" maxTokens must be a positive integer`);
|
|
643
|
+
if (entry.maxTokens !== void 0) configuredMaxTokens.set(entry.id, entry.maxTokens);
|
|
644
|
+
return {
|
|
645
|
+
...base,
|
|
646
|
+
id: entry.id,
|
|
647
|
+
name: entry.name ?? base?.name ?? entry.id,
|
|
648
|
+
api,
|
|
649
|
+
provider,
|
|
650
|
+
baseUrl,
|
|
651
|
+
input: declaredInput(entry.input) ?? base?.input ?? [...request.defaultInput],
|
|
652
|
+
cost: base?.cost ?? NO_COST,
|
|
653
|
+
contextWindow,
|
|
654
|
+
maxTokens,
|
|
655
|
+
...resolveModelReasoning(provider, entry, base),
|
|
656
|
+
...resolveModelCompat(provider, entry, request.compat, base, api)
|
|
646
657
|
};
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
});
|
|
652
|
-
}
|
|
653
|
-
return value;
|
|
654
|
-
};
|
|
655
|
-
var __disposeResources = (function(SuppressedError) {
|
|
656
|
-
return function(env) {
|
|
657
|
-
function fail(e) {
|
|
658
|
-
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
659
|
-
env.hasError = true;
|
|
660
|
-
}
|
|
661
|
-
var r, s = 0;
|
|
662
|
-
function next() {
|
|
663
|
-
while (r = env.stack.pop()) try {
|
|
664
|
-
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
|
|
665
|
-
if (r.dispose) {
|
|
666
|
-
var result = r.dispose.call(r.value);
|
|
667
|
-
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) {
|
|
668
|
-
fail(e);
|
|
669
|
-
return next();
|
|
670
|
-
});
|
|
671
|
-
} else s |= 1;
|
|
672
|
-
} catch (e) {
|
|
673
|
-
fail(e);
|
|
674
|
-
}
|
|
675
|
-
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
|
|
676
|
-
if (env.hasError) throw env.error;
|
|
677
|
-
}
|
|
678
|
-
return next();
|
|
679
|
-
};
|
|
680
|
-
})(typeof SuppressedError === "function" ? SuppressedError : function(error, suppressed, message) {
|
|
681
|
-
var e = new Error(message);
|
|
682
|
-
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
683
|
-
});
|
|
684
|
-
/** Copy profile stream knobs into pi-ai's common option vocabulary. */
|
|
685
|
-
function profileOptions(profile, reasoning, apiKey) {
|
|
686
|
-
const enabledReasoning = reasoning === "off" ? void 0 : reasoning;
|
|
658
|
+
});
|
|
659
|
+
for (const [field] of configuredCompatEntries(request.compat)) {
|
|
660
|
+
const takers = compatProtocols(field);
|
|
661
|
+
if (models.some((model) => takers.includes(model.api))) continue;
|
|
662
|
+
invalid(provider, `sets compat "${field}", but no model on the route speaks a protocol that takes it; it exists on ${takers.join(", ")}`);
|
|
663
|
+
}
|
|
687
664
|
return {
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
...profile.thinkingBudgets === void 0 ? {} : { thinkingBudgets: profile.thinkingBudgets },
|
|
691
|
-
...profile.cacheRetention === void 0 ? {} : { cacheRetention: profile.cacheRetention },
|
|
692
|
-
...profile.transport === void 0 ? {} : { transport: profile.transport },
|
|
693
|
-
...profile.timeoutMs === void 0 ? {} : { timeoutMs: profile.timeoutMs },
|
|
694
|
-
...profile.websocketConnectTimeoutMs === void 0 ? {} : { websocketConnectTimeoutMs: profile.websocketConnectTimeoutMs },
|
|
695
|
-
maxRetries: 0
|
|
665
|
+
models,
|
|
666
|
+
configuredMaxTokens
|
|
696
667
|
};
|
|
697
668
|
}
|
|
669
|
+
//#endregion
|
|
670
|
+
//#region lib/types/provider.js
|
|
698
671
|
/**
|
|
699
|
-
*
|
|
700
|
-
*
|
|
701
|
-
*
|
|
702
|
-
*
|
|
703
|
-
*
|
|
704
|
-
*
|
|
705
|
-
*
|
|
706
|
-
*
|
|
707
|
-
*
|
|
708
|
-
*
|
|
709
|
-
*
|
|
672
|
+
* Construction of the pi-ai `Provider` that one configured route registers into
|
|
673
|
+
* the adapter's `Models` collection.
|
|
674
|
+
*
|
|
675
|
+
* Two constructions, one decision: a route the installed catalog ships, whose
|
|
676
|
+
* profile does not override the wire protocol, **reuses that catalog provider**
|
|
677
|
+
* with its models replaced — the catalog provider owns API implementations this
|
|
678
|
+
* package cannot reconstruct (Bedrock loads its Smithy module through a
|
|
679
|
+
* separate entry point), so rebuilding it from parts would silently narrow
|
|
680
|
+
* which providers work. Every other route — one pi-ai has never heard of, or a
|
|
681
|
+
* catalog route pointed at a different protocol — is built by `createProvider`
|
|
682
|
+
* over the protocol table below.
|
|
683
|
+
*
|
|
684
|
+
* Credentials never reach this module's storage: the harness resolves a route's
|
|
685
|
+
* key through `ctx.credentials` before the request enters pi-ai and hands it
|
|
686
|
+
* over as a stream option, which `Models` presents to `resolve()` as the
|
|
687
|
+
* credential key.
|
|
688
|
+
*
|
|
689
|
+
* @module nomix-llm-pi-ai/provider
|
|
710
690
|
*/
|
|
711
|
-
function describableReasoningLevel(model, effort) {
|
|
712
|
-
if (effort === void 0) return void 0;
|
|
713
|
-
return getSupportedThinkingLevels(model).some((level) => level === effort) ? effort : void 0;
|
|
714
|
-
}
|
|
715
|
-
/** Validate an explicit Harness/profile effort without invoking pi-ai's clamp. */
|
|
716
|
-
function resolveReasoningLevel(model, effort) {
|
|
717
|
-
if (effort === void 0) return void 0;
|
|
718
|
-
if (getSupportedThinkingLevels(model).some((level) => level === effort)) return effort;
|
|
719
|
-
throw new LlmError(`pi-ai provider "${model.provider}" model "${model.id}" does not support reasoning effort "${effort}"`, "UNSUPPORTED_REASONING_EFFORT");
|
|
720
|
-
}
|
|
721
691
|
/**
|
|
722
|
-
*
|
|
692
|
+
* Wire protocols a configured route may name, mapped to pi-ai's lazily loaded
|
|
693
|
+
* implementations. Each entry is the factory that pi-ai's matching provider
|
|
694
|
+
* factory uses, so a hand-declared route reaches exactly the implementation a
|
|
695
|
+
* catalog route would.
|
|
723
696
|
*
|
|
724
|
-
*
|
|
725
|
-
*
|
|
726
|
-
*
|
|
727
|
-
*
|
|
728
|
-
*
|
|
729
|
-
*
|
|
730
|
-
*
|
|
731
|
-
*
|
|
732
|
-
*
|
|
733
|
-
*
|
|
734
|
-
*
|
|
735
|
-
* @returns the `reasoning` field, or an empty object when none can be offered.
|
|
697
|
+
* The table is deliberately narrow: the protocols a hand-declared route
|
|
698
|
+
* actually reaches for today, each completely describable with a key, an
|
|
699
|
+
* endpoint, and headers. Bedrock signs with SigV4 over AWS credentials and a
|
|
700
|
+
* region, Vertex needs a project, a location, and application-default
|
|
701
|
+
* credentials, Azure needs provider environment plus an api-version, and Codex
|
|
702
|
+
* authenticates through OAuth — none of which this configuration shape can
|
|
703
|
+
* express, so offering them would hand back a provider that cannot
|
|
704
|
+
* authenticate. The remainder are absent for want of a consumer rather than a
|
|
705
|
+
* blocker: each is one line here once a deployment needs it. Catalog routes
|
|
706
|
+
* still reach every protocol through their own provider; only an explicit
|
|
707
|
+
* override is refused.
|
|
736
708
|
*/
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
709
|
+
const PROTOCOLS = {
|
|
710
|
+
"openai-completions": openAICompletionsApi,
|
|
711
|
+
"openai-responses": openAIResponsesApi,
|
|
712
|
+
"anthropic-messages": anthropicMessagesApi
|
|
713
|
+
};
|
|
714
|
+
/**
|
|
715
|
+
* Every wire protocol a configured route may name, most-reached first. The
|
|
716
|
+
* order is the table's and therefore stable; a configuration surface offering
|
|
717
|
+
* a choice presents the first as its default, which is why the protocol a
|
|
718
|
+
* hand-declared gateway most often speaks — and the one endpoint interrogation
|
|
719
|
+
* can read — leads.
|
|
720
|
+
* @returns the supported protocol identifiers.
|
|
721
|
+
*/
|
|
722
|
+
function supportedProtocols() {
|
|
723
|
+
return Object.keys(PROTOCOLS);
|
|
746
724
|
}
|
|
747
|
-
/**
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
725
|
+
/**
|
|
726
|
+
* Api-key auth for a route the harness authenticates itself. `Models` calls
|
|
727
|
+
* this after the adapter has already resolved the route's credential, so a
|
|
728
|
+
* missing key here is not this layer's failure: a named-but-unresolvable
|
|
729
|
+
* reference has already failed the request with `MISSING_CREDENTIAL`, and a
|
|
730
|
+
* route naming no credential at all is deliberately unauthenticated. Reporting
|
|
731
|
+
* it as configured hands the decision to the protocol, which is where the
|
|
732
|
+
* requirement actually lives — pi-ai's OpenAI-compatible implementation, for
|
|
733
|
+
* one, still insists on a key or an `Authorization` header of its own.
|
|
734
|
+
* @param name - display name used as the resolution's status label.
|
|
735
|
+
* @returns the api-key auth for a harness-authenticated route.
|
|
736
|
+
*/
|
|
737
|
+
function harnessApiKeyAuth(name) {
|
|
751
738
|
return {
|
|
752
|
-
|
|
753
|
-
|
|
739
|
+
name,
|
|
740
|
+
resolve: ({ credential }) => Promise.resolve({
|
|
741
|
+
auth: credential?.key === void 0 ? {} : { apiKey: credential.key },
|
|
742
|
+
source: name
|
|
743
|
+
})
|
|
754
744
|
};
|
|
755
745
|
}
|
|
756
746
|
/**
|
|
757
|
-
*
|
|
758
|
-
* profiles, so a configuration change reaches the next request without a
|
|
759
|
-
* restart; model descriptors come from the collection those profiles built.
|
|
760
|
-
*/
|
|
761
|
-
var PiAiAdapter = class extends LlmAdapter {
|
|
762
|
-
config;
|
|
763
|
-
snapshot;
|
|
764
|
-
constructor(config) {
|
|
765
|
-
super();
|
|
766
|
-
this.config = config;
|
|
767
|
-
}
|
|
768
|
-
/**
|
|
769
|
-
* The snapshot for the current profiles. Resolution memoizes its result, so
|
|
770
|
-
* an unchanged configuration is recognized by identity; a changed one gets a
|
|
771
|
-
* brand-new collection, leaving any snapshot an operation already captured
|
|
772
|
-
* untouched for as long as that operation holds it.
|
|
773
|
-
*/
|
|
774
|
-
current() {
|
|
775
|
-
const profiles = this.config.profiles();
|
|
776
|
-
if (this.snapshot?.profiles === profiles) return this.snapshot;
|
|
777
|
-
const models = createModels();
|
|
778
|
-
for (const profile of profiles.values()) models.setProvider(profile.piProvider);
|
|
779
|
-
this.snapshot = {
|
|
780
|
-
profiles,
|
|
781
|
-
models
|
|
782
|
-
};
|
|
783
|
-
return this.snapshot;
|
|
784
|
-
}
|
|
785
|
-
/** The profile for one route within one snapshot, or the not-owned failure. */
|
|
786
|
-
profileOf(snapshot, provider) {
|
|
787
|
-
const profile = snapshot.profiles.get(provider);
|
|
788
|
-
if (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider "${provider}"`, "NO_ADAPTER");
|
|
789
|
-
return profile;
|
|
790
|
-
}
|
|
791
|
-
/** The configured descriptor for one exact route/model pair within one snapshot. */
|
|
792
|
-
modelOf(snapshot, provider, model) {
|
|
793
|
-
this.profileOf(snapshot, provider);
|
|
794
|
-
const resolved = snapshot.models.getModel(provider, model);
|
|
795
|
-
if (resolved === void 0) throw new LlmError(`pi-ai provider "${provider}" has no configured model "${model}"`, "UNKNOWN_MODEL");
|
|
796
|
-
return resolved;
|
|
797
|
-
}
|
|
798
|
-
providerInfo(provider) {
|
|
799
|
-
return {
|
|
800
|
-
id: provider,
|
|
801
|
-
name: this.current().profiles.get(provider)?.displayName ?? provider
|
|
802
|
-
};
|
|
803
|
-
}
|
|
804
|
-
providerRetryPolicy(provider) {
|
|
805
|
-
return this.current().profiles.get(provider)?.retryPolicy;
|
|
806
|
-
}
|
|
807
|
-
listModels(provider) {
|
|
808
|
-
return Promise.resolve().then(() => {
|
|
809
|
-
const snapshot = this.current();
|
|
810
|
-
this.profileOf(snapshot, provider);
|
|
811
|
-
return snapshot.models.getModels(provider).map((model) => ({
|
|
812
|
-
provider,
|
|
813
|
-
id: model.id,
|
|
814
|
-
name: model.name,
|
|
815
|
-
inputModalities: [...model.input]
|
|
816
|
-
}));
|
|
817
|
-
});
|
|
818
|
-
}
|
|
819
|
-
resolveModel(provider, model, _signal) {
|
|
820
|
-
return Promise.resolve().then(() => {
|
|
821
|
-
const snapshot = this.current();
|
|
822
|
-
const profile = this.profileOf(snapshot, provider);
|
|
823
|
-
const resolvedModel = this.modelOf(snapshot, provider, model);
|
|
824
|
-
const defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);
|
|
825
|
-
const configuredMaxTokens = profile.configuredMaxTokens.get(model);
|
|
826
|
-
return {
|
|
827
|
-
provider,
|
|
828
|
-
id: model,
|
|
829
|
-
name: resolvedModel.name,
|
|
830
|
-
inputModalities: [...resolvedModel.input],
|
|
831
|
-
context: { contextWindow: resolvedModel.contextWindow },
|
|
832
|
-
...configuredMaxTokens === void 0 ? {} : { defaultMaxTokens: configuredMaxTokens },
|
|
833
|
-
...reasoningInfo(resolvedModel, defaultLevel)
|
|
834
|
-
};
|
|
835
|
-
});
|
|
836
|
-
}
|
|
837
|
-
async *stream(options) {
|
|
838
|
-
const env_1 = {
|
|
839
|
-
stack: [],
|
|
840
|
-
error: void 0,
|
|
841
|
-
hasError: false
|
|
842
|
-
};
|
|
843
|
-
try {
|
|
844
|
-
if (options.stop !== void 0) throw new LlmError("llm-pi-ai does not support GenerateOptions.stop", "UNSUPPORTED_OPTION");
|
|
845
|
-
const snapshot = this.current();
|
|
846
|
-
const profile = this.profileOf(snapshot, options.provider);
|
|
847
|
-
const model = this.modelOf(snapshot, options.provider, options.model);
|
|
848
|
-
const reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);
|
|
849
|
-
const apiKey = await this.config.resolveApiKey(options.provider, profile);
|
|
850
|
-
const consumer = new AbortController();
|
|
851
|
-
const upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);
|
|
852
|
-
const streamIdleTimeoutMs = profile.streamIdleTimeoutMs;
|
|
853
|
-
const watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, "LLM_STREAM_IDLE_TIMEOUT"), false);
|
|
854
|
-
try {
|
|
855
|
-
const containsImage = options.messages.some((message) => contentHasImage(message.content));
|
|
856
|
-
if (containsImage && !model.input.includes("image")) throw new LlmError(`pi-ai model "${model.id}" does not support image input`, "UNSUPPORTED_CONTENT");
|
|
857
|
-
const attachments = containsImage ? this.config.resolveAttachments?.() : void 0;
|
|
858
|
-
if (containsImage && attachments === void 0) throw new LlmError("pi-ai image input requires the durable attachment service", "UNSUPPORTED_CONTENT");
|
|
859
|
-
const onReplayDegrade = (reason) => {
|
|
860
|
-
this.config.onReplayDegrade?.({
|
|
861
|
-
provider: options.provider,
|
|
862
|
-
model: options.model,
|
|
863
|
-
reason
|
|
864
|
-
});
|
|
865
|
-
};
|
|
866
|
-
const context = attachments === void 0 ? toPiContext(options, void 0, onReplayDegrade) : await toPiContext(options, attachments, onReplayDegrade);
|
|
867
|
-
const iterator = toStreamChunks(snapshot.models.streamSimple(model, context, {
|
|
868
|
-
...profileOptions(profile, reasoning, apiKey),
|
|
869
|
-
...options.temperature === void 0 ? {} : { temperature: options.temperature },
|
|
870
|
-
...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },
|
|
871
|
-
...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },
|
|
872
|
-
signal: watchdog.signal,
|
|
873
|
-
headers: requestHeaders(profile.headers)
|
|
874
|
-
}), model.contextWindow)[Symbol.asyncIterator]();
|
|
875
|
-
let exhausted = false;
|
|
876
|
-
try {
|
|
877
|
-
while (true) {
|
|
878
|
-
const result = await watchdog.next(iterator);
|
|
879
|
-
const timeout = timeoutOf(watchdog.signal, "LLM_STREAM_IDLE_TIMEOUT");
|
|
880
|
-
if (timeout !== void 0) throw timeout;
|
|
881
|
-
if (result.done) {
|
|
882
|
-
exhausted = true;
|
|
883
|
-
return;
|
|
884
|
-
}
|
|
885
|
-
yield result.value;
|
|
886
|
-
}
|
|
887
|
-
} finally {
|
|
888
|
-
if (!exhausted) {
|
|
889
|
-
consumer.abort("pi-ai stream consumer stopped");
|
|
890
|
-
try {
|
|
891
|
-
await iterator.return(void 0);
|
|
892
|
-
} catch (_abortedSdkTeardown) {}
|
|
893
|
-
}
|
|
894
|
-
}
|
|
895
|
-
} catch (error) {
|
|
896
|
-
if (timeoutOf(watchdog.signal, "LLM_STREAM_IDLE_TIMEOUT") !== void 0) throw new LlmError(`pi-ai stream idle timeout after ${streamIdleTimeoutMs}ms`, "TIMEOUT", { cause: error });
|
|
897
|
-
if (options.signal?.aborted) throw new LlmError("pi-ai request aborted by caller", "ABORTED", { cause: error });
|
|
898
|
-
throw error;
|
|
899
|
-
} finally {
|
|
900
|
-
consumer.abort("pi-ai stream consumer stopped");
|
|
901
|
-
}
|
|
902
|
-
} catch (e_1) {
|
|
903
|
-
env_1.error = e_1;
|
|
904
|
-
env_1.hasError = true;
|
|
905
|
-
} finally {
|
|
906
|
-
__disposeResources(env_1);
|
|
907
|
-
}
|
|
908
|
-
}
|
|
909
|
-
};
|
|
910
|
-
//#endregion
|
|
911
|
-
//#region lib/types/catalog.js
|
|
912
|
-
/**
|
|
913
|
-
* Materialization of one provider route's model catalog. The installed pi-ai
|
|
914
|
-
* catalog supplies defaults keyed by model id, and a profile's own model
|
|
915
|
-
* entries override them field by field, so a route naming a catalog provider
|
|
916
|
-
* stays configuration-free while a route pi-ai has never heard of is fully
|
|
917
|
-
* describable from `settings.yaml`.
|
|
747
|
+
* The auth one route resolves its credential through.
|
|
918
748
|
*
|
|
919
|
-
*
|
|
920
|
-
*
|
|
921
|
-
*
|
|
749
|
+
* A catalog route keeps the installed provider's own auth, which is what
|
|
750
|
+
* preserves provider-native ambient discovery for a profile naming no
|
|
751
|
+
* credential. That holds even when the profile repoints the protocol: which
|
|
752
|
+
* environment a provider reads is a property of the provider, not of the wire
|
|
753
|
+
* format its models speak.
|
|
922
754
|
*
|
|
923
|
-
*
|
|
755
|
+
* The single addition covers a catalog provider that offers no api-key method
|
|
756
|
+
* at all. pi-ai resolves a request's `apiKey` override only when the provider
|
|
757
|
+
* declares one (`resolveProviderAuth` checks `provider.auth.apiKey` before
|
|
758
|
+
* honouring the override), so an OAuth-only provider — `openai-codex` is the
|
|
759
|
+
* one the installed catalog ships — would refuse a profile's explicit key with
|
|
760
|
+
* `Provider is not configured` before any request went out. Adding the harness
|
|
761
|
+
* method beside the provider's own restores that route. A keyless profile adds
|
|
762
|
+
* nothing and still reports the honest refusal, because this adapter resolves
|
|
763
|
+
* credentials through its own seam and holds no OAuth store to fall back on.
|
|
764
|
+
* @param spec - the resolved route facts.
|
|
765
|
+
* @param catalog - the installed catalog provider, when pi-ai ships one.
|
|
766
|
+
* @returns the auth to construct this route's provider with.
|
|
924
767
|
*/
|
|
768
|
+
function routeAuth(spec, catalog) {
|
|
769
|
+
if (catalog === void 0) return { apiKey: harnessApiKeyAuth(spec.displayName) };
|
|
770
|
+
if (catalog.auth.apiKey !== void 0 || !spec.namesCredential) return catalog.auth;
|
|
771
|
+
return {
|
|
772
|
+
...catalog.auth,
|
|
773
|
+
apiKey: harnessApiKeyAuth(spec.displayName)
|
|
774
|
+
};
|
|
775
|
+
}
|
|
925
776
|
/**
|
|
926
|
-
*
|
|
927
|
-
*
|
|
928
|
-
*
|
|
777
|
+
* Reuse an installed catalog provider with this route's models and identity.
|
|
778
|
+
* Model dispatch stays with the catalog provider, so its API implementations,
|
|
779
|
+
* compatibility quirks, and ambient credential discovery are preserved exactly.
|
|
780
|
+
* Catalog-owned dynamic refresh is dropped: this route's catalog is the
|
|
781
|
+
* settings document, and a background refresh would contradict it.
|
|
929
782
|
*/
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
}
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
}
|
|
783
|
+
function reuseCatalogProvider(base, spec) {
|
|
784
|
+
const baseUrl = spec.baseURL ?? base.baseUrl;
|
|
785
|
+
return {
|
|
786
|
+
id: spec.provider,
|
|
787
|
+
name: spec.displayName,
|
|
788
|
+
...baseUrl === void 0 ? {} : { baseUrl },
|
|
789
|
+
auth: routeAuth(spec, base),
|
|
790
|
+
getModels: () => spec.models,
|
|
791
|
+
stream: (model, context, options) => base.stream(model, context, options),
|
|
792
|
+
streamSimple: (model, context, options) => base.streamSimple(model, context, options)
|
|
793
|
+
};
|
|
794
|
+
}
|
|
941
795
|
/**
|
|
942
|
-
*
|
|
943
|
-
*
|
|
944
|
-
*
|
|
945
|
-
*
|
|
946
|
-
* schema materializes `[]` for an absent array.
|
|
947
|
-
* @param configured - the list a `models` or `modelOverrides` entry supplied.
|
|
948
|
-
* @returns the declared modalities, or `undefined` to ask the next level.
|
|
796
|
+
* Build the pi-ai provider for one resolved route.
|
|
797
|
+
* @param spec - the resolved route facts.
|
|
798
|
+
* @returns the provider to register in the adapter's `Models` collection.
|
|
799
|
+
* @throws Error when the route names a wire protocol this build cannot serve.
|
|
949
800
|
*/
|
|
950
|
-
function
|
|
951
|
-
|
|
801
|
+
function buildProvider(spec) {
|
|
802
|
+
const catalog = catalogProvider(spec.provider);
|
|
803
|
+
if (catalog !== void 0 && spec.api === void 0) return reuseCatalogProvider(catalog, spec);
|
|
804
|
+
const factory = spec.api === void 0 ? void 0 : PROTOCOLS[spec.api];
|
|
805
|
+
if (factory === void 0) throw new Error(`llm-pi-ai: provider "${spec.provider}" names api "${spec.api}", which this build cannot serve; supported protocols are ${supportedProtocols().join(", ")}`);
|
|
806
|
+
return createProvider({
|
|
807
|
+
id: spec.provider,
|
|
808
|
+
name: spec.displayName,
|
|
809
|
+
...spec.baseURL === void 0 ? {} : { baseUrl: spec.baseURL },
|
|
810
|
+
auth: routeAuth(spec, catalog),
|
|
811
|
+
models: spec.models,
|
|
812
|
+
api: factory()
|
|
813
|
+
});
|
|
952
814
|
}
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
off: true,
|
|
956
|
-
minimal: true,
|
|
957
|
-
low: true,
|
|
958
|
-
medium: true,
|
|
959
|
-
high: true,
|
|
960
|
-
xhigh: true,
|
|
961
|
-
max: true
|
|
962
|
-
});
|
|
963
|
-
/** Reasoning-dispatch wire formats a profile may name, most-reached first. */
|
|
964
|
-
const SUPPORTED_THINKING_FORMATS = Object.keys({
|
|
965
|
-
"openai": true,
|
|
966
|
-
"deepseek": true,
|
|
967
|
-
"openrouter": true,
|
|
968
|
-
"together": true,
|
|
969
|
-
"zai": true,
|
|
970
|
-
"qwen": true,
|
|
971
|
-
"string-thinking": true,
|
|
972
|
-
"ant-ling": true
|
|
973
|
-
});
|
|
974
|
-
let providerIndex;
|
|
815
|
+
//#endregion
|
|
816
|
+
//#region lib/types/config.js
|
|
975
817
|
/**
|
|
976
|
-
*
|
|
977
|
-
*
|
|
978
|
-
* provider
|
|
979
|
-
*
|
|
818
|
+
* Configuration schema and provider-profile validation for the pi-ai adapter.
|
|
819
|
+
* Profiles are a dict keyed by provider route, so the composition base and a
|
|
820
|
+
* user-settings layer merge per provider and the route set is structural.
|
|
821
|
+
*
|
|
822
|
+
* A route key is not required to name an installed pi-ai provider. When it does,
|
|
823
|
+
* that provider's endpoint, protocol, display name, and model catalog are the
|
|
824
|
+
* profile's defaults and the profile overrides them field by field; when it does
|
|
825
|
+
* not, the profile is the whole provider declaration. Resolution therefore ends
|
|
826
|
+
* in a built pi-ai `Provider` per route: everything a request needs is decided
|
|
827
|
+
* once, while the configuration key that made a route unserviceable can still be
|
|
828
|
+
* named in the failure.
|
|
829
|
+
*
|
|
830
|
+
* @module nomix-llm-pi-ai/config
|
|
980
831
|
*/
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
832
|
+
/** Default maximum idle interval while an adapter stream read is outstanding. */
|
|
833
|
+
const DEFAULT_STREAM_IDLE_TIMEOUT_MS = 3e5;
|
|
834
|
+
/**
|
|
835
|
+
* Default request-level bound on base64-encoded image payload. Every image in
|
|
836
|
+
* history is re-encoded into every request body, so an unbounded conversation
|
|
837
|
+
* eventually exceeds a provider or gateway request-size cap and the session
|
|
838
|
+
* can never complete another request. The 20MiB default admits fifteen 1MiB
|
|
839
|
+
* request versions after base64 expansion and reserves request capacity for
|
|
840
|
+
* system prompts, history, tools, and JSON.
|
|
841
|
+
* Deployments behind stricter gateways lower it per route.
|
|
842
|
+
*/
|
|
843
|
+
const DEFAULT_MAX_REQUEST_IMAGE_BYTES = 20 * 1024 * 1024;
|
|
844
|
+
/** Default total-pixel budget preserves the complete 2048px normalized attachment. */
|
|
845
|
+
const DEFAULT_REQUEST_IMAGE_PIXEL_BUDGET = 2048 * 2048;
|
|
846
|
+
/** Default raw encoded-byte cap before inline base64 expansion. */
|
|
847
|
+
const DEFAULT_REQUEST_IMAGE_MAX_BYTES = 1024 * 1024;
|
|
848
|
+
/** Context capacity assumed for a model neither configuration nor the catalog sizes. */
|
|
849
|
+
const DEFAULT_CONTEXT_WINDOW = 262144;
|
|
850
|
+
/** Output capability assumed for a model neither configuration nor the catalog sizes. */
|
|
851
|
+
const DEFAULT_MAX_TOKENS = 32768;
|
|
852
|
+
/**
|
|
853
|
+
* Modalities assumed for a model neither configuration nor the catalog
|
|
854
|
+
* declares. Text is the floor every supported protocol certainly carries, so
|
|
855
|
+
* this is the absence of a declaration rather than a guess at the endpoint:
|
|
856
|
+
* nothing can interrogate a gateway for its modalities, and the two wrong
|
|
857
|
+
* answers do not cost the same. Under-claiming refuses the image before it is
|
|
858
|
+
* attached, naming the model. Over-claiming admits one the provider then
|
|
859
|
+
* rejects mid-turn, after the message is durable, leaving the session
|
|
860
|
+
* repeating a request that cannot succeed.
|
|
861
|
+
*/
|
|
862
|
+
const DEFAULT_INPUT = ["text"];
|
|
863
|
+
const thinkingBudgets = z.object({
|
|
864
|
+
minimal: z.number(),
|
|
865
|
+
low: z.number(),
|
|
866
|
+
medium: z.number(),
|
|
867
|
+
high: z.number()
|
|
868
|
+
});
|
|
869
|
+
/**
|
|
870
|
+
* One `chat_template_kwargs` value. The `$var` member is pi-ai's placeholder
|
|
871
|
+
* for a value dispatch fills from the request's thinking state, which is what
|
|
872
|
+
* makes a chat-template gateway configurable without restating its template.
|
|
873
|
+
*/
|
|
874
|
+
const chatTemplateKwarg = z.union([
|
|
875
|
+
z.string(),
|
|
876
|
+
z.number(),
|
|
877
|
+
z.boolean(),
|
|
878
|
+
z.const(null),
|
|
879
|
+
z.object({
|
|
880
|
+
$var: z.union(CHAT_TEMPLATE_VARS).required(),
|
|
881
|
+
omitWhenOff: z.boolean()
|
|
882
|
+
})
|
|
883
|
+
]);
|
|
884
|
+
const compatProfile = z.object({
|
|
885
|
+
supportsStore: z.boolean(),
|
|
886
|
+
supportsDeveloperRole: z.boolean(),
|
|
887
|
+
supportsReasoningEffort: z.boolean(),
|
|
888
|
+
supportsUsageInStreaming: z.boolean(),
|
|
889
|
+
maxTokensField: z.union(MAX_TOKENS_FIELDS),
|
|
890
|
+
requiresToolResultName: z.boolean(),
|
|
891
|
+
requiresAssistantAfterToolResult: z.boolean(),
|
|
892
|
+
requiresThinkingAsText: z.boolean(),
|
|
893
|
+
requiresReasoningContentOnAssistantMessages: z.boolean(),
|
|
894
|
+
thinkingFormat: z.union(SUPPORTED_THINKING_FORMATS),
|
|
895
|
+
chatTemplateKwargs: z.dict(chatTemplateKwarg),
|
|
896
|
+
supportsStrictMode: z.boolean(),
|
|
897
|
+
cacheControlFormat: z.union(CACHE_CONTROL_FORMATS),
|
|
898
|
+
supportsLongCacheRetention: z.boolean(),
|
|
899
|
+
supportsEagerToolInputStreaming: z.boolean(),
|
|
900
|
+
supportsCacheControlOnTools: z.boolean(),
|
|
901
|
+
supportsTemperature: z.boolean(),
|
|
902
|
+
forceAdaptiveThinking: z.boolean(),
|
|
903
|
+
allowEmptySignature: z.boolean(),
|
|
904
|
+
supportsStrictTools: z.boolean()
|
|
905
|
+
});
|
|
906
|
+
/**
|
|
907
|
+
* Keys are the offered levels, values their wire spellings. A valueless key
|
|
908
|
+
* (`off:`) survives validation because schemastery passes nullable data
|
|
909
|
+
* through before any member schema runs — `z.const(null)` only controls the
|
|
910
|
+
* error for non-null wrong values and what a configuration UI renders.
|
|
911
|
+
* Only resolution decides which levels may leave the value empty, so the
|
|
912
|
+
* diagnostic can name the route and model. The assertion narrows
|
|
913
|
+
* schemastery's `Dict`, which types every literal key as required; dict
|
|
914
|
+
* validation checks only present keys, so the runtime value is a partial record.
|
|
915
|
+
*/
|
|
916
|
+
const reasoningEfforts = z.dict(z.union([z.string(), z.const(null)]), z.union(THINKING_LEVELS));
|
|
917
|
+
/** The fields a `models` entry and a `modelOverrides` value share; only the id's home differs. */
|
|
918
|
+
const modelFields = {
|
|
919
|
+
name: z.string(),
|
|
920
|
+
contextWindow: z.number().step(1).min(1),
|
|
921
|
+
maxTokens: z.number().step(1).min(1),
|
|
922
|
+
input: z.array(z.union(MODALITIES)),
|
|
923
|
+
reasoningEfforts: z.union([z.const(false), reasoningEfforts]),
|
|
924
|
+
compat: compatProfile
|
|
925
|
+
};
|
|
926
|
+
const modelProfile = z.object({
|
|
927
|
+
id: z.string().required(),
|
|
928
|
+
...modelFields
|
|
929
|
+
});
|
|
930
|
+
/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */
|
|
931
|
+
const modelOverride = z.object(modelFields);
|
|
932
|
+
const profile = z.object({
|
|
933
|
+
apiKeyEnv: z.string().role("credential-ref"),
|
|
934
|
+
displayName: z.string(),
|
|
935
|
+
api: z.union(supportedProtocols()),
|
|
936
|
+
baseURL: z.string(),
|
|
937
|
+
models: z.array(modelProfile),
|
|
938
|
+
modelOverrides: z.dict(modelOverride),
|
|
939
|
+
compat: compatProfile,
|
|
940
|
+
defaultContextWindow: z.number().step(1).min(1).default(DEFAULT_CONTEXT_WINDOW),
|
|
941
|
+
defaultMaxTokens: z.number().step(1).min(1).default(DEFAULT_MAX_TOKENS),
|
|
942
|
+
defaultInput: z.array(z.union(MODALITIES)).default([...DEFAULT_INPUT]),
|
|
943
|
+
headers: z.dict(z.string()),
|
|
944
|
+
reasoning: z.union(THINKING_LEVELS),
|
|
945
|
+
thinkingBudgets,
|
|
946
|
+
cacheRetention: z.union([
|
|
947
|
+
"none",
|
|
948
|
+
"short",
|
|
949
|
+
"long"
|
|
950
|
+
]),
|
|
951
|
+
transport: z.union([
|
|
952
|
+
"sse",
|
|
953
|
+
"websocket",
|
|
954
|
+
"websocket-cached",
|
|
955
|
+
"auto"
|
|
956
|
+
]),
|
|
957
|
+
timeoutMs: z.natural(),
|
|
958
|
+
websocketConnectTimeoutMs: z.natural(),
|
|
959
|
+
streamIdleTimeoutMs: z.number().min(Number.MIN_VALUE).max(MAX_TIMER_DELAY_MS).default(DEFAULT_STREAM_IDLE_TIMEOUT_MS),
|
|
960
|
+
maxRequestImageBytes: z.number().step(1).min(1).default(DEFAULT_MAX_REQUEST_IMAGE_BYTES),
|
|
961
|
+
requestImagePixelBudget: z.number().step(1).min(1).default(DEFAULT_REQUEST_IMAGE_PIXEL_BUDGET),
|
|
962
|
+
requestImageMaxBytes: z.number().step(1).min(1).default(DEFAULT_REQUEST_IMAGE_MAX_BYTES),
|
|
963
|
+
retryPolicy: RetryPolicySchema
|
|
964
|
+
});
|
|
965
|
+
/** Runtime schema for {@link Config}. */
|
|
966
|
+
const Config = z.object({ providers: z.dict(profile).default({}) });
|
|
967
|
+
/**
|
|
968
|
+
* Reject a section this adapter could not serve. Registered as the settings
|
|
969
|
+
* namespace's validator, so an unserviceable profile is refused where it is
|
|
970
|
+
* *written* — `settings.mutate` answers `settings-rejected` with the offending
|
|
971
|
+
* route and model named — instead of being stored and then quietly disabling
|
|
972
|
+
* every route in the namespace. It stays a validator rather than a schema
|
|
973
|
+
* transform because the schema is also the shape a configuration surface
|
|
974
|
+
* renders and the value an absent section resolves to; wrapping it would break
|
|
975
|
+
* both.
|
|
976
|
+
* @param config - the resolved section to check.
|
|
977
|
+
* @throws Error naming the route and model that cannot be served.
|
|
978
|
+
*/
|
|
979
|
+
function assertServiceable(config) {
|
|
980
|
+
resolveProfiles(config.providers);
|
|
981
|
+
}
|
|
982
|
+
/** Reject removed pre-release profile fields and name their replacements. */
|
|
983
|
+
function rejectRemovedFields(provider, source) {
|
|
984
|
+
const legacy = source;
|
|
985
|
+
if ("provider" in legacy) throw new Error(`llm-pi-ai: provider "${provider}" sets "provider", which moved to the providers dict key`);
|
|
986
|
+
if ("maxRetries" in legacy || "maxRetryDelayMs" in legacy) throw new Error(`llm-pi-ai: provider "${provider}" sets maxRetries or maxRetryDelayMs, which were removed; compose agent recovery with nomix-llm-retry`);
|
|
987
|
+
}
|
|
988
|
+
/**
|
|
989
|
+
* Validate profiles and return a detached route-keyed map suitable for
|
|
990
|
+
* per-request reads. This is the one explicit resolve step, so an omitted dict
|
|
991
|
+
* resolves to the empty (dormant) route set here rather than through a hidden
|
|
992
|
+
* fallback, and each route's models and pi-ai provider are materialized once.
|
|
993
|
+
* @param providers - configured provider profiles keyed by route.
|
|
994
|
+
* @returns validated profiles in configuration order.
|
|
995
|
+
*/
|
|
996
|
+
function resolveProfiles(providers) {
|
|
997
|
+
if (Array.isArray(providers)) throw new Error("llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles");
|
|
998
|
+
const entries = Object.entries(providers ?? {});
|
|
999
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
1000
|
+
for (const [provider, source] of entries) {
|
|
1001
|
+
rejectRemovedFields(provider, source);
|
|
1002
|
+
if (provider.length === 0) throw new Error("llm-pi-ai: provider names must be non-empty");
|
|
1003
|
+
if (source.baseURL !== void 0 && source.baseURL.length === 0) throw new Error(`llm-pi-ai: provider "${provider}" has an empty baseURL`);
|
|
1004
|
+
if (source.displayName !== void 0 && source.displayName.length === 0) throw new Error(`llm-pi-ai: provider "${provider}" has an empty displayName`);
|
|
1005
|
+
const streamIdleTimeoutMs = source.streamIdleTimeoutMs ?? 3e5;
|
|
1006
|
+
if (!Number.isFinite(streamIdleTimeoutMs) || streamIdleTimeoutMs <= 0 || streamIdleTimeoutMs > MAX_TIMER_DELAY_MS) throw new Error(`llm-pi-ai: provider "${provider}" streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);
|
|
1007
|
+
const maxRequestImageBytes = source.maxRequestImageBytes ?? 20971520;
|
|
1008
|
+
if (!Number.isInteger(maxRequestImageBytes) || maxRequestImageBytes <= 0) throw new Error(`llm-pi-ai: provider "${provider}" maxRequestImageBytes must be a positive integer`);
|
|
1009
|
+
const requestImagePixelBudget = source.requestImagePixelBudget ?? 4194304;
|
|
1010
|
+
if (!Number.isSafeInteger(requestImagePixelBudget) || requestImagePixelBudget <= 0) throw new Error(`llm-pi-ai: provider "${provider}" requestImagePixelBudget must be a positive safe integer`);
|
|
1011
|
+
const requestImageMaxBytes = source.requestImageMaxBytes ?? 1048576;
|
|
1012
|
+
if (!Number.isSafeInteger(requestImageMaxBytes) || requestImageMaxBytes <= 0) throw new Error(`llm-pi-ai: provider "${provider}" requestImageMaxBytes must be a positive safe integer`);
|
|
1013
|
+
const defaultInput = [...source.defaultInput ?? DEFAULT_INPUT];
|
|
1014
|
+
if (defaultInput.length === 0) throw new Error(`llm-pi-ai: provider "${provider}" defaultInput must name at least one modality`);
|
|
1015
|
+
const displayName = source.displayName ?? provider;
|
|
1016
|
+
const catalog = resolveRouteModels({
|
|
1017
|
+
provider,
|
|
1018
|
+
...source.api === void 0 ? {} : { api: source.api },
|
|
1019
|
+
...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },
|
|
1020
|
+
...source.models === void 0 ? {} : { models: source.models },
|
|
1021
|
+
...source.modelOverrides === void 0 ? {} : { modelOverrides: source.modelOverrides },
|
|
1022
|
+
...source.compat === void 0 ? {} : { compat: source.compat },
|
|
1023
|
+
defaultInput,
|
|
1024
|
+
defaultContextWindow: source.defaultContextWindow ?? 262144,
|
|
1025
|
+
defaultMaxTokens: source.defaultMaxTokens ?? 32768
|
|
1026
|
+
});
|
|
1027
|
+
const { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, ...rest } = source;
|
|
1028
|
+
resolved.set(provider, {
|
|
1029
|
+
...rest,
|
|
1030
|
+
provider,
|
|
1031
|
+
displayName,
|
|
1032
|
+
...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },
|
|
1033
|
+
streamIdleTimeoutMs,
|
|
1034
|
+
maxRequestImageBytes,
|
|
1035
|
+
requestImagePixelBudget,
|
|
1036
|
+
requestImageMaxBytes,
|
|
1037
|
+
retryPolicy: resolveRetryPolicy(retryPolicy, `llm-pi-ai: provider "${provider}" retryPolicy`),
|
|
1038
|
+
...rest.headers === void 0 ? {} : { headers: { ...rest.headers } },
|
|
1039
|
+
...rest.thinkingBudgets === void 0 ? {} : { thinkingBudgets: { ...rest.thinkingBudgets } },
|
|
1040
|
+
configuredMaxTokens: catalog.configuredMaxTokens,
|
|
1041
|
+
piProvider: buildProvider({
|
|
1042
|
+
provider,
|
|
1043
|
+
displayName,
|
|
1044
|
+
...source.api === void 0 ? {} : { api: source.api },
|
|
1045
|
+
...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },
|
|
1046
|
+
models: catalog.models,
|
|
1047
|
+
namesCredential: apiKeyEnv !== void 0
|
|
1048
|
+
})
|
|
1049
|
+
});
|
|
1050
|
+
}
|
|
1051
|
+
return resolved;
|
|
1052
|
+
}
|
|
1053
|
+
//#endregion
|
|
1054
|
+
//#region lib/types/context.js
|
|
1055
|
+
/**
|
|
1056
|
+
* Harness request-history conversion into pi-ai's Context vocabulary.
|
|
1057
|
+
*
|
|
1058
|
+
* @module nomix-llm-pi-ai/context
|
|
1059
|
+
*/
|
|
1060
|
+
/** Join the text blocks of a harness message. */
|
|
1061
|
+
function flattenText(message) {
|
|
1062
|
+
return message.content.filter((block) => block.type === "text").map((block) => block.text).join("");
|
|
1063
|
+
}
|
|
1064
|
+
/** Flatten text recursively inside one tool result. */
|
|
1065
|
+
function toolResultText(blocks) {
|
|
1066
|
+
return blocks.map((block) => block.type === "text" ? block.text : block.type === "tool-result" ? toolResultText(block.content) : "").join("");
|
|
1067
|
+
}
|
|
1068
|
+
/** Reject image roles that pi-ai cannot replay before request-size offloading can replace them. */
|
|
1069
|
+
function assertSupportedImageRoles(messages) {
|
|
1070
|
+
for (const message of messages) if (message.role !== "user" && contentHasImage(message.content)) throw new LlmError(`pi-ai cannot represent an image in an in-history ${message.role} message`, "UNSUPPORTED_CONTENT");
|
|
1071
|
+
}
|
|
1072
|
+
async function userContent(blocks, requestImages) {
|
|
1073
|
+
const content = [];
|
|
1074
|
+
for (const block of blocks) switch (block.type) {
|
|
1075
|
+
case "text":
|
|
1076
|
+
if (block.text.length > 0) content.push({
|
|
1077
|
+
type: "text",
|
|
1078
|
+
text: block.text
|
|
1079
|
+
});
|
|
1080
|
+
break;
|
|
1081
|
+
case "image": {
|
|
1082
|
+
const version = requestImages.get(block.attachment.attachmentId);
|
|
1083
|
+
content.push({
|
|
1084
|
+
type: "text",
|
|
1085
|
+
text: requestImageHandleText(version)
|
|
1086
|
+
});
|
|
1087
|
+
content.push({
|
|
1088
|
+
type: "image",
|
|
1089
|
+
data: Buffer.from(version.data).toString("base64"),
|
|
1090
|
+
mimeType: version.mediaType
|
|
1091
|
+
});
|
|
1092
|
+
break;
|
|
1093
|
+
}
|
|
1094
|
+
case "tool-result":
|
|
1095
|
+
{
|
|
1096
|
+
const nested = await userContent(block.content, requestImages);
|
|
1097
|
+
if (typeof nested === "string") {
|
|
1098
|
+
if (nested.length > 0) content.push({
|
|
1099
|
+
type: "text",
|
|
1100
|
+
text: nested
|
|
1101
|
+
});
|
|
1102
|
+
} else content.push(...nested);
|
|
1103
|
+
}
|
|
1104
|
+
break;
|
|
1105
|
+
default: break;
|
|
1106
|
+
}
|
|
1107
|
+
if (content.every((block) => block.type === "text")) return content.map((block) => block.text).join("");
|
|
1108
|
+
return content;
|
|
1109
|
+
}
|
|
1110
|
+
function collectImageRefs(blocks, refs) {
|
|
1111
|
+
for (const block of blocks) if (block.type === "image") refs.set(block.attachment.attachmentId, block.attachment);
|
|
1112
|
+
else if (block.type === "tool-result") collectImageRefs(block.content, refs);
|
|
1113
|
+
}
|
|
1114
|
+
async function prepareRequestImages(messages, attachments, policy, signal) {
|
|
1115
|
+
const refs = /* @__PURE__ */ new Map();
|
|
1116
|
+
for (const message of messages) collectImageRefs(message.content, refs);
|
|
1117
|
+
const orderedRefs = [...refs.values()];
|
|
1118
|
+
const prepared = await Promise.all(orderedRefs.map((ref) => attachments.readImageRequest(ref, policy, signal)));
|
|
1119
|
+
const versions = /* @__PURE__ */ new Map();
|
|
1120
|
+
for (const [index, ref] of orderedRefs.entries()) versions.set(ref.attachmentId, prepared[index]);
|
|
1121
|
+
return versions;
|
|
1122
|
+
}
|
|
1123
|
+
function toolsOf(options) {
|
|
1124
|
+
return options.tools?.map((tool) => ({
|
|
1125
|
+
name: tool.name,
|
|
1126
|
+
description: tool.description,
|
|
1127
|
+
parameters: tool.parameters
|
|
1128
|
+
}));
|
|
1129
|
+
}
|
|
1130
|
+
/** Assemble the request-level pi-ai context envelope shared by both conversion paths. */
|
|
1131
|
+
function piContext(options, messages) {
|
|
1132
|
+
const tools = toolsOf(options);
|
|
1133
|
+
return {
|
|
1134
|
+
...options.system !== void 0 ? { systemPrompt: options.system } : {},
|
|
1135
|
+
messages,
|
|
1136
|
+
...tools !== void 0 && tools.length > 0 ? { tools } : {}
|
|
1137
|
+
};
|
|
1138
|
+
}
|
|
1139
|
+
function textOnlyContext(options, onReplayDegrade) {
|
|
1140
|
+
const toolNames = /* @__PURE__ */ new Map();
|
|
1141
|
+
const messages = [];
|
|
1142
|
+
for (const message of options.messages) {
|
|
1143
|
+
if (contentHasImage(message.content)) throw new LlmError("pi-ai image conversion requires the durable attachment service", "UNSUPPORTED_CONTENT");
|
|
1144
|
+
if (message.role === "system") {
|
|
1145
|
+
messages.push({
|
|
1146
|
+
role: "user",
|
|
1147
|
+
content: flattenText(message),
|
|
1148
|
+
timestamp: 0
|
|
1149
|
+
});
|
|
1150
|
+
continue;
|
|
1151
|
+
}
|
|
1152
|
+
if (message.role === "assistant") {
|
|
1153
|
+
const assistant = toPiAssistant(message, onReplayDegrade);
|
|
1154
|
+
for (const block of assistant.content) if (block.type === "toolCall") toolNames.set(CallId(block.id), block.name);
|
|
1155
|
+
messages.push(assistant);
|
|
1156
|
+
continue;
|
|
1157
|
+
}
|
|
1158
|
+
const text = flattenText(message);
|
|
1159
|
+
const results = message.content.filter((block) => block.type === "tool-result");
|
|
1160
|
+
if (text.length > 0 || results.length === 0) messages.push({
|
|
1161
|
+
role: "user",
|
|
1162
|
+
content: text,
|
|
1163
|
+
timestamp: 0
|
|
1164
|
+
});
|
|
1165
|
+
for (const result of results) messages.push({
|
|
1166
|
+
role: "toolResult",
|
|
1167
|
+
toolCallId: result.toolCallId,
|
|
1168
|
+
toolName: toolNames.get(result.toolCallId) ?? "unknown",
|
|
1169
|
+
content: [{
|
|
1170
|
+
type: "text",
|
|
1171
|
+
text: toolResultText(result.content) || "(no output)"
|
|
1172
|
+
}],
|
|
1173
|
+
isError: result.isError ?? false,
|
|
1174
|
+
timestamp: 0
|
|
1175
|
+
});
|
|
1176
|
+
}
|
|
1177
|
+
return piContext(options, messages);
|
|
984
1178
|
}
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
* @param provider - provider route key.
|
|
988
|
-
* @returns the catalog provider, or `undefined` for a route pi-ai does not ship.
|
|
989
|
-
*/
|
|
990
|
-
function catalogProvider(provider) {
|
|
991
|
-
return catalogProviders().get(provider);
|
|
1179
|
+
function toPiContext(options, attachments, onReplayDegrade, maxRequestImageBytes, requestImagePolicy) {
|
|
1180
|
+
return attachments === void 0 ? textOnlyContext(options, onReplayDegrade) : toPiContextWithImages(options, attachments, onReplayDegrade, maxRequestImageBytes, requestImagePolicy);
|
|
992
1181
|
}
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
1182
|
+
async function toPiContextWithImages(options, attachments, onReplayDegrade, maxRequestImageBytes, requestImagePolicy = {
|
|
1183
|
+
maxPixels: DEFAULT_REQUEST_IMAGE_PIXEL_BUDGET,
|
|
1184
|
+
maxBytes: DEFAULT_REQUEST_IMAGE_MAX_BYTES
|
|
1185
|
+
}) {
|
|
1186
|
+
assertSupportedImageRoles(options.messages);
|
|
1187
|
+
const requestMessages = offloadRequestImagesWithPolicy(options.messages, {
|
|
1188
|
+
representation: "base64",
|
|
1189
|
+
...maxRequestImageBytes === void 0 ? {} : { maxBytes: maxRequestImageBytes },
|
|
1190
|
+
byteQuantum: 1,
|
|
1191
|
+
byteLength: (ref) => Math.min(ref.bytes, requestImagePolicy.maxBytes)
|
|
1192
|
+
});
|
|
1193
|
+
const requestImages = await prepareRequestImages(requestMessages, attachments, requestImagePolicy, options.signal);
|
|
1194
|
+
const exactMessages = offloadRequestImagesWithPolicy(requestMessages, {
|
|
1195
|
+
representation: "base64",
|
|
1196
|
+
...maxRequestImageBytes === void 0 ? {} : { maxBytes: maxRequestImageBytes },
|
|
1197
|
+
byteQuantum: 1,
|
|
1198
|
+
byteLength: (ref) => requestImages.get(ref.attachmentId).bytes
|
|
1199
|
+
});
|
|
1200
|
+
const toolNames = /* @__PURE__ */ new Map();
|
|
1201
|
+
const messages = [];
|
|
1202
|
+
for (const message of exactMessages) {
|
|
1203
|
+
if (message.role === "system") {
|
|
1204
|
+
messages.push({
|
|
1205
|
+
role: "user",
|
|
1206
|
+
content: flattenText(message),
|
|
1207
|
+
timestamp: 0
|
|
1208
|
+
});
|
|
1209
|
+
continue;
|
|
1210
|
+
}
|
|
1211
|
+
if (message.role === "assistant") {
|
|
1212
|
+
const assistant = toPiAssistant(message, onReplayDegrade);
|
|
1213
|
+
for (const block of assistant.content) if (block.type === "toolCall") toolNames.set(CallId(block.id), block.name);
|
|
1214
|
+
messages.push(assistant);
|
|
1215
|
+
continue;
|
|
1216
|
+
}
|
|
1217
|
+
const content = await userContent(message.content.filter((block) => block.type !== "tool-result"), requestImages);
|
|
1218
|
+
const results = message.content.filter((block) => block.type === "tool-result");
|
|
1219
|
+
if (content.length > 0 || results.length === 0) messages.push({
|
|
1220
|
+
role: "user",
|
|
1221
|
+
content,
|
|
1222
|
+
timestamp: 0
|
|
1223
|
+
});
|
|
1224
|
+
for (const result of results) {
|
|
1225
|
+
const resultContent = await userContent(result.content, requestImages);
|
|
1226
|
+
messages.push({
|
|
1227
|
+
role: "toolResult",
|
|
1228
|
+
toolCallId: result.toolCallId,
|
|
1229
|
+
toolName: toolNames.get(result.toolCallId) ?? "unknown",
|
|
1230
|
+
content: typeof resultContent === "string" ? [{
|
|
1231
|
+
type: "text",
|
|
1232
|
+
text: resultContent || "(no output)"
|
|
1233
|
+
}] : resultContent,
|
|
1234
|
+
isError: result.isError ?? false,
|
|
1235
|
+
timestamp: 0
|
|
1236
|
+
});
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
return piContext(options, messages);
|
|
999
1240
|
}
|
|
1241
|
+
//#endregion
|
|
1242
|
+
//#region lib/types/stream.js
|
|
1000
1243
|
/**
|
|
1001
|
-
*
|
|
1002
|
-
* method — the only authentication this adapter obtains on its own.
|
|
1244
|
+
* pi-ai assistant event translation into the Harness streaming protocol.
|
|
1003
1245
|
*
|
|
1004
|
-
*
|
|
1005
|
-
*
|
|
1006
|
-
*
|
|
1007
|
-
*
|
|
1008
|
-
*
|
|
1009
|
-
* leaves nothing for this adapter to authenticate with, and the posture such a
|
|
1010
|
-
* provider invites — no key configured, credentials discovered by the provider
|
|
1011
|
-
* — fails every request with `Provider is not configured`.
|
|
1012
|
-
* @param provider - provider route key.
|
|
1013
|
-
* @returns whether the catalog provider takes an api key; false for a route
|
|
1014
|
-
* pi-ai does not ship, which the caller answers for separately.
|
|
1015
|
-
*/
|
|
1016
|
-
function catalogProviderTakesApiKey(provider) {
|
|
1017
|
-
return catalogProvider(provider)?.auth.apiKey !== void 0;
|
|
1018
|
-
}
|
|
1019
|
-
/**
|
|
1020
|
-
* The installed catalog models for one route, indexed by model id.
|
|
1021
|
-
* @param provider - provider route key.
|
|
1022
|
-
* @returns catalog models by id; empty for a route pi-ai does not ship.
|
|
1023
|
-
*/
|
|
1024
|
-
function catalogModels(provider) {
|
|
1025
|
-
if (!catalogProviders().has(provider)) return /* @__PURE__ */ new Map();
|
|
1026
|
-
const models = getBuiltinModels(provider);
|
|
1027
|
-
return new Map(models.map((model) => [model.id, model]));
|
|
1028
|
-
}
|
|
1029
|
-
/** Report a route the deployment cannot serve, naming the settings key at fault. */
|
|
1030
|
-
function invalid(provider, detail) {
|
|
1031
|
-
throw new Error(`llm-pi-ai: provider "${provider}" ${detail}`);
|
|
1032
|
-
}
|
|
1033
|
-
/**
|
|
1034
|
-
* The one wire protocol a catalog route's shipped models agree on. This is what
|
|
1035
|
-
* lets a deployment add a model the installed catalog has not caught up with —
|
|
1036
|
-
* a provider's newest release — without restating the protocol its siblings
|
|
1037
|
-
* already use. A route whose shipped models disagree (an OpenAI-style catalog
|
|
1038
|
-
* spanning Responses and Chat Completions) has no such answer, so a model it
|
|
1039
|
-
* does not describe must name its protocol at the route.
|
|
1246
|
+
* pi-ai tool-call arguments are parsed objects while the Harness keeps their
|
|
1247
|
+
* raw JSON representation. pi-ai also reports failures as terminal stream
|
|
1248
|
+
* events, which this module maps into Harness finish chunks.
|
|
1249
|
+
*
|
|
1250
|
+
* @module nomix-llm-pi-ai/stream
|
|
1040
1251
|
*/
|
|
1041
|
-
function sharedCatalogApi(defaults) {
|
|
1042
|
-
const apis = /* @__PURE__ */ new Set();
|
|
1043
|
-
for (const model of defaults.values()) apis.add(model.api);
|
|
1044
|
-
return apis.size === 1 ? [...apis][0] : void 0;
|
|
1045
|
-
}
|
|
1046
1252
|
/**
|
|
1047
|
-
*
|
|
1048
|
-
*
|
|
1049
|
-
*
|
|
1050
|
-
* decided explicitly: declared levels carry their wire spelling, undeclared
|
|
1051
|
-
* levels are pinned to `null` (unsupported). Pinning matters because pi-ai's
|
|
1052
|
-
* own defaulting is asymmetric — an absent key means "supported" for the five
|
|
1053
|
-
* base levels but "unsupported" for `xhigh`/`max` — and a profile author
|
|
1054
|
-
* should not need to know that. A declared `off` with no value is the one
|
|
1055
|
-
* exception: it stays absent from the map, which pi-ai reads as "supported,
|
|
1056
|
-
* send nothing" — the correct dispatch where not thinking is the parameter's
|
|
1057
|
-
* absence — while `off` with a value sends that value.
|
|
1058
|
-
* @param provider - provider route key, for diagnostics.
|
|
1059
|
-
* @param entry - the configured model entry.
|
|
1060
|
-
* @param base - the installed catalog entry of the same id, when one exists.
|
|
1061
|
-
* @returns the reasoning fields the materialized model carries.
|
|
1253
|
+
* Map pi-ai usage (reasoning folded into output by pi-ai).
|
|
1254
|
+
* @param usage - cumulative usage from the terminal pi-ai event.
|
|
1255
|
+
* @returns harness counts; cache fields appear only when non-zero (pi-ai reports zeros, not absence).
|
|
1062
1256
|
*/
|
|
1063
|
-
function
|
|
1064
|
-
const efforts = entry.reasoningEfforts;
|
|
1065
|
-
if (efforts === void 0) return { reasoning: base?.reasoning ?? false };
|
|
1066
|
-
if (efforts === false) return { reasoning: false };
|
|
1067
|
-
if (efforts === null || Object.keys(efforts).length === 0) invalid(provider, `model "${entry.id}" has an empty reasoningEfforts; declare the offered levels, set false for a non-reasoning model, or omit the field to keep the installed catalog's capability`);
|
|
1068
|
-
const declared = THINKING_LEVELS.flatMap((level) => {
|
|
1069
|
-
const wire = efforts[level];
|
|
1070
|
-
return wire === void 0 ? [] : [[level, wire]];
|
|
1071
|
-
});
|
|
1072
|
-
for (const [level, wire] of declared) if (wire === null) {
|
|
1073
|
-
if (level !== "off") invalid(provider, `model "${entry.id}" reasoningEfforts.${level} needs the wire value dispatch should send; only "off" may leave it empty`);
|
|
1074
|
-
} else if (wire.length === 0) invalid(provider, `model "${entry.id}" reasoningEfforts.${level} must not be an empty string`);
|
|
1075
|
-
if (!declared.some(([level]) => level !== "off")) invalid(provider, `model "${entry.id}" reasoningEfforts offers no level beyond "off"; declare a thinking level, or set reasoningEfforts to false for a non-reasoning model`);
|
|
1076
|
-
const map = {};
|
|
1077
|
-
for (const level of THINKING_LEVELS) {
|
|
1078
|
-
const wire = efforts[level];
|
|
1079
|
-
if (wire === void 0) map[level] = null;
|
|
1080
|
-
else if (wire !== null) map[level] = wire;
|
|
1081
|
-
}
|
|
1257
|
+
function mapUsage(usage) {
|
|
1082
1258
|
return {
|
|
1083
|
-
|
|
1084
|
-
|
|
1259
|
+
inputTokens: usage.input,
|
|
1260
|
+
outputTokens: usage.output,
|
|
1261
|
+
...usage.cacheRead > 0 ? { cacheReadTokens: usage.cacheRead } : {},
|
|
1262
|
+
...usage.cacheWrite > 0 ? { cacheWriteTokens: usage.cacheWrite } : {}
|
|
1085
1263
|
};
|
|
1086
1264
|
}
|
|
1265
|
+
function classifyPiAiError(message) {
|
|
1266
|
+
if (/\b(?:401|403)\b/.test(message)) return "AUTH";
|
|
1267
|
+
if (isQuotaExceededError(message)) return QUOTA_EXCEEDED_CODE;
|
|
1268
|
+
if (/\b429\b|rate.?limit/i.test(message)) return "RATE_LIMIT";
|
|
1269
|
+
if (/\b413\b|failed to buffer the request body:\s*length limit exceeded|payload too large|request body too large/i.test(message)) return "INVALID_REQUEST";
|
|
1270
|
+
if (/\b400\b|invalid.?request/i.test(message)) return "INVALID_REQUEST";
|
|
1271
|
+
if (/\b5\d\d\b/.test(message)) return "SERVER";
|
|
1272
|
+
if (/\btime(?:d)?\s*out\b|timeout/i.test(message)) return "TIMEOUT";
|
|
1273
|
+
if (/stream ended (?:before|without)\b/i.test(message)) return "TRANSPORT";
|
|
1274
|
+
if (/\b(?:network|connection|socket|fetch)\b|\bECONN[A-Z]+\b/i.test(message) || /\b(?:other side closed|HTTP2 request did not get a response|WebSocket closed unexpectedly)\b/i.test(message) || /\bterminated\b|premature close/i.test(message)) return "TRANSPORT";
|
|
1275
|
+
return "PI_AI_ERROR";
|
|
1276
|
+
}
|
|
1087
1277
|
/**
|
|
1088
|
-
*
|
|
1089
|
-
*
|
|
1090
|
-
*
|
|
1091
|
-
*
|
|
1092
|
-
*
|
|
1093
|
-
*
|
|
1094
|
-
*
|
|
1095
|
-
* posture as the route-level `reasoning` default, which also must not fail
|
|
1096
|
-
* models it does not fit.
|
|
1097
|
-
* @param provider - provider route key, for diagnostics.
|
|
1098
|
-
* @param entry - the configured model entry.
|
|
1099
|
-
* @param route - the route-level switches, when any.
|
|
1100
|
-
* @param base - the installed catalog entry of the same id, when one exists.
|
|
1101
|
-
* @param api - the model's resolved wire protocol.
|
|
1102
|
-
* @returns a `compat` field to spread into the model, or nothing.
|
|
1278
|
+
* Map a terminal pi-ai event to the harness finish reason.
|
|
1279
|
+
* @param message - the assistant message carried by the `done` or `error` event.
|
|
1280
|
+
* @param contextWindow - resolved catalog capacity for usage-based overflow detection.
|
|
1281
|
+
* @returns the mapped harness reason. Recognized error text, `stop` usage above
|
|
1282
|
+
* `contextWindow`, and zero-output `length` usage that fills the window map
|
|
1283
|
+
* to `CONTEXT_WINDOW_EXCEEDED`; a `stop` with no content blocks maps to an
|
|
1284
|
+
* `EMPTY_RESPONSE` error.
|
|
1103
1285
|
*/
|
|
1104
|
-
function
|
|
1105
|
-
const
|
|
1106
|
-
const
|
|
1107
|
-
if (
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1286
|
+
function mapStopReason(message, contextWindow) {
|
|
1287
|
+
const piAiOverflow = isContextOverflow(message, contextWindow);
|
|
1288
|
+
const harnessOverflow = message.stopReason === "error" && message.errorMessage !== void 0 && isContextWindowExceededError(message.errorMessage);
|
|
1289
|
+
if (piAiOverflow || harnessOverflow) return {
|
|
1290
|
+
kind: "error",
|
|
1291
|
+
failure: {
|
|
1292
|
+
message: message.errorMessage ?? `pi-ai detected context overflow for model "${message.model}"`,
|
|
1293
|
+
code: CONTEXT_WINDOW_EXCEEDED_CODE
|
|
1294
|
+
}
|
|
1295
|
+
};
|
|
1296
|
+
switch (message.stopReason) {
|
|
1297
|
+
case "stop":
|
|
1298
|
+
if (message.content.length === 0) return {
|
|
1299
|
+
kind: "error",
|
|
1300
|
+
failure: {
|
|
1301
|
+
message: `model "${message.model}" returned a completed response with no content`,
|
|
1302
|
+
code: EMPTY_RESPONSE_CODE
|
|
1303
|
+
}
|
|
1304
|
+
};
|
|
1305
|
+
return { kind: "stop" };
|
|
1306
|
+
case "length": return { kind: "max-tokens" };
|
|
1307
|
+
case "toolUse": return { kind: "tool-calls" };
|
|
1308
|
+
case "aborted": return {
|
|
1309
|
+
kind: "aborted",
|
|
1310
|
+
failure: {
|
|
1311
|
+
message: message.errorMessage ?? "pi-ai stream aborted",
|
|
1312
|
+
code: "ABORTED"
|
|
1313
|
+
}
|
|
1314
|
+
};
|
|
1315
|
+
case "error": {
|
|
1316
|
+
const text = message.errorMessage ?? "pi-ai stream error";
|
|
1317
|
+
return {
|
|
1318
|
+
kind: "error",
|
|
1319
|
+
failure: {
|
|
1320
|
+
message: text,
|
|
1321
|
+
code: classifyPiAiError(text)
|
|
1322
|
+
}
|
|
1323
|
+
};
|
|
1324
|
+
}
|
|
1111
1325
|
}
|
|
1112
|
-
return { compat: {
|
|
1113
|
-
...base?.api === api ? base.compat : void 0,
|
|
1114
|
-
...thinkingFormat === void 0 ? {} : { thinkingFormat },
|
|
1115
|
-
...supportsReasoningEffort === void 0 ? {} : { supportsReasoningEffort }
|
|
1116
|
-
} };
|
|
1117
1326
|
}
|
|
1118
1327
|
/**
|
|
1119
|
-
*
|
|
1120
|
-
*
|
|
1121
|
-
*
|
|
1122
|
-
*
|
|
1123
|
-
* @param
|
|
1124
|
-
* @returns the
|
|
1328
|
+
* Translate the pi-ai event stream into StreamChunks. pi-ai never throws
|
|
1329
|
+
* mid-stream — failures arrive as `error` events, which become error/aborted
|
|
1330
|
+
* `finish` chunks (the harness protocol's other error-delivery style).
|
|
1331
|
+
* @param events - one assistant turn's pi-ai event stream.
|
|
1332
|
+
* @param contextWindow - resolved catalog capacity for usage-based overflow detection.
|
|
1333
|
+
* @returns the harness chunks, ending with `usage` then `finish`; throws
|
|
1334
|
+
* `LlmError` (`STREAM_CLOSED`) if the source ends without a terminal event.
|
|
1125
1335
|
*/
|
|
1126
|
-
function
|
|
1127
|
-
const
|
|
1128
|
-
const
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1336
|
+
async function* toStreamChunks(events, contextWindow) {
|
|
1337
|
+
const toolIds = /* @__PURE__ */ new Map();
|
|
1338
|
+
for await (const event of events) switch (event.type) {
|
|
1339
|
+
case "start": break;
|
|
1340
|
+
case "text_start":
|
|
1341
|
+
yield {
|
|
1342
|
+
type: "block-start",
|
|
1343
|
+
index: event.contentIndex,
|
|
1344
|
+
blockType: "text"
|
|
1345
|
+
};
|
|
1346
|
+
break;
|
|
1347
|
+
case "text_delta":
|
|
1348
|
+
yield {
|
|
1349
|
+
type: "text-delta",
|
|
1350
|
+
index: event.contentIndex,
|
|
1351
|
+
text: event.delta
|
|
1352
|
+
};
|
|
1353
|
+
break;
|
|
1354
|
+
case "text_end":
|
|
1355
|
+
yield {
|
|
1356
|
+
type: "block-end",
|
|
1357
|
+
index: event.contentIndex,
|
|
1358
|
+
block: {
|
|
1359
|
+
type: "text",
|
|
1360
|
+
text: event.content
|
|
1361
|
+
}
|
|
1362
|
+
};
|
|
1363
|
+
break;
|
|
1364
|
+
case "thinking_start":
|
|
1365
|
+
yield {
|
|
1366
|
+
type: "block-start",
|
|
1367
|
+
index: event.contentIndex,
|
|
1368
|
+
blockType: "reasoning"
|
|
1369
|
+
};
|
|
1370
|
+
break;
|
|
1371
|
+
case "thinking_delta":
|
|
1372
|
+
yield {
|
|
1373
|
+
type: "reasoning-delta",
|
|
1374
|
+
index: event.contentIndex,
|
|
1375
|
+
text: event.delta
|
|
1376
|
+
};
|
|
1377
|
+
break;
|
|
1378
|
+
case "thinking_end":
|
|
1379
|
+
yield {
|
|
1380
|
+
type: "block-end",
|
|
1381
|
+
index: event.contentIndex,
|
|
1382
|
+
block: {
|
|
1383
|
+
type: "reasoning",
|
|
1384
|
+
text: event.content
|
|
1385
|
+
}
|
|
1386
|
+
};
|
|
1387
|
+
break;
|
|
1388
|
+
case "toolcall_start": {
|
|
1389
|
+
const partial = event.partial.content[event.contentIndex];
|
|
1390
|
+
const id = partial?.type === "toolCall" ? partial.id : "";
|
|
1391
|
+
const name = partial?.type === "toolCall" ? partial.name : "";
|
|
1392
|
+
toolIds.set(event.contentIndex, {
|
|
1393
|
+
id,
|
|
1394
|
+
name
|
|
1395
|
+
});
|
|
1396
|
+
yield {
|
|
1397
|
+
type: "block-start",
|
|
1398
|
+
index: event.contentIndex,
|
|
1399
|
+
blockType: "tool-call"
|
|
1400
|
+
};
|
|
1401
|
+
break;
|
|
1402
|
+
}
|
|
1403
|
+
case "toolcall_delta": {
|
|
1404
|
+
const known = toolIds.get(event.contentIndex);
|
|
1405
|
+
yield {
|
|
1406
|
+
type: "tool-call-delta",
|
|
1407
|
+
index: event.contentIndex,
|
|
1408
|
+
id: CallId(known?.id ?? ""),
|
|
1409
|
+
...known?.name !== void 0 && known.name.length > 0 ? { name: known.name } : {},
|
|
1410
|
+
argumentsDelta: event.delta
|
|
1411
|
+
};
|
|
1412
|
+
break;
|
|
1413
|
+
}
|
|
1414
|
+
case "toolcall_end":
|
|
1415
|
+
yield {
|
|
1416
|
+
type: "block-end",
|
|
1417
|
+
index: event.contentIndex,
|
|
1418
|
+
block: {
|
|
1419
|
+
type: "tool-call",
|
|
1420
|
+
id: CallId(event.toolCall.id),
|
|
1421
|
+
name: event.toolCall.name,
|
|
1422
|
+
arguments: JSON.stringify(event.toolCall.arguments)
|
|
1423
|
+
}
|
|
1424
|
+
};
|
|
1425
|
+
break;
|
|
1426
|
+
case "done":
|
|
1427
|
+
yield {
|
|
1428
|
+
type: "usage",
|
|
1429
|
+
usage: mapUsage(event.message.usage)
|
|
1430
|
+
};
|
|
1431
|
+
yield {
|
|
1432
|
+
type: "finish",
|
|
1433
|
+
reason: mapStopReason(event.message, contextWindow),
|
|
1434
|
+
replayState: toPiReplayState(event.message)
|
|
1435
|
+
};
|
|
1436
|
+
return;
|
|
1437
|
+
case "error":
|
|
1438
|
+
yield {
|
|
1439
|
+
type: "usage",
|
|
1440
|
+
usage: mapUsage(event.error.usage)
|
|
1441
|
+
};
|
|
1442
|
+
yield {
|
|
1443
|
+
type: "finish",
|
|
1444
|
+
reason: mapStopReason(event.error, contextWindow)
|
|
1445
|
+
};
|
|
1446
|
+
return;
|
|
1138
1447
|
}
|
|
1139
|
-
|
|
1140
|
-
id: model.id,
|
|
1141
|
-
...overrides[model.id]
|
|
1142
|
-
}));
|
|
1143
|
-
if (entries.length === 0) invalid(provider, "resolves no models; the installed catalog does not describe this route, so its models must be listed in configuration");
|
|
1144
|
-
const routeApi = sharedCatalogApi(defaults);
|
|
1145
|
-
const routeCompatDefined = request.compat?.thinkingFormat !== void 0 || request.compat?.supportsReasoningEffort !== void 0;
|
|
1146
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1147
|
-
const configuredMaxTokens = /* @__PURE__ */ new Map();
|
|
1148
|
-
const models = entries.map((entry) => {
|
|
1149
|
-
if (entry.id.length === 0) invalid(provider, "has a model with an empty id");
|
|
1150
|
-
if (seen.has(entry.id)) invalid(provider, `lists model "${entry.id}" more than once`);
|
|
1151
|
-
seen.add(entry.id);
|
|
1152
|
-
const base = defaults.get(entry.id);
|
|
1153
|
-
const api = request.api ?? base?.api ?? routeApi;
|
|
1154
|
-
if (api === void 0) invalid(provider, `model "${entry.id}" needs an api; the installed catalog does not describe it, so set the route's api to the wire protocol its endpoint speaks`);
|
|
1155
|
-
const baseUrl = request.baseURL ?? base?.baseUrl ?? providerBaseUrl;
|
|
1156
|
-
if (baseUrl === void 0) invalid(provider, `model "${entry.id}" needs a baseURL; the installed catalog does not describe this route`);
|
|
1157
|
-
const contextWindow = entry.contextWindow ?? base?.contextWindow ?? request.defaultContextWindow;
|
|
1158
|
-
if (!Number.isInteger(contextWindow) || contextWindow <= 0) invalid(provider, `model "${entry.id}" contextWindow must be a positive integer`);
|
|
1159
|
-
const maxTokens = entry.maxTokens ?? base?.maxTokens ?? request.defaultMaxTokens;
|
|
1160
|
-
if (!Number.isInteger(maxTokens) || maxTokens <= 0) invalid(provider, `model "${entry.id}" maxTokens must be a positive integer`);
|
|
1161
|
-
if (entry.maxTokens !== void 0) configuredMaxTokens.set(entry.id, entry.maxTokens);
|
|
1162
|
-
return {
|
|
1163
|
-
...base,
|
|
1164
|
-
id: entry.id,
|
|
1165
|
-
name: entry.name ?? base?.name ?? entry.id,
|
|
1166
|
-
api,
|
|
1167
|
-
provider,
|
|
1168
|
-
baseUrl,
|
|
1169
|
-
input: declaredInput(entry.input) ?? base?.input ?? [...request.defaultInput],
|
|
1170
|
-
cost: base?.cost ?? NO_COST,
|
|
1171
|
-
contextWindow,
|
|
1172
|
-
maxTokens,
|
|
1173
|
-
...resolveModelReasoning(provider, entry, base),
|
|
1174
|
-
...resolveModelCompat(provider, entry, request.compat, base, api)
|
|
1175
|
-
};
|
|
1176
|
-
});
|
|
1177
|
-
if (routeCompatDefined && !models.some((model) => model.api === "openai-completions")) invalid(provider, "sets compat reasoning switches, but no model on the route speaks openai-completions; thinkingFormat and supportsReasoningEffort exist only on that protocol");
|
|
1178
|
-
return {
|
|
1179
|
-
models,
|
|
1180
|
-
configuredMaxTokens
|
|
1181
|
-
};
|
|
1448
|
+
throw new LlmError("pi-ai event stream ended without done/error", "STREAM_CLOSED");
|
|
1182
1449
|
}
|
|
1183
1450
|
//#endregion
|
|
1184
|
-
//#region lib/types/
|
|
1451
|
+
//#region lib/types/adapter.js
|
|
1185
1452
|
/**
|
|
1186
|
-
*
|
|
1187
|
-
* the adapter's `Models` collection.
|
|
1188
|
-
*
|
|
1189
|
-
* Two constructions, one decision: a route the installed catalog ships, whose
|
|
1190
|
-
* profile does not override the wire protocol, **reuses that catalog provider**
|
|
1191
|
-
* with its models replaced — the catalog provider owns API implementations this
|
|
1192
|
-
* package cannot reconstruct (Bedrock loads its Smithy module through a
|
|
1193
|
-
* separate entry point), so rebuilding it from parts would silently narrow
|
|
1194
|
-
* which providers work. Every other route — one pi-ai has never heard of, or a
|
|
1195
|
-
* catalog route pointed at a different protocol — is built by `createProvider`
|
|
1196
|
-
* over the protocol table below.
|
|
1453
|
+
* Generic pi-ai-backed implementation of the Harness LLM seam.
|
|
1197
1454
|
*
|
|
1198
|
-
*
|
|
1199
|
-
*
|
|
1200
|
-
*
|
|
1201
|
-
*
|
|
1455
|
+
* Each resolution produces one **immutable** snapshot — the profiles plus a
|
|
1456
|
+
* `Models` collection holding the `Provider` each route built — and an
|
|
1457
|
+
* operation captures a whole snapshot before its first `await`. A
|
|
1458
|
+
* configuration change builds a *new* collection rather than mutating the one
|
|
1459
|
+
* in use, because `Models.streamSimple()` is lazy: it resolves the provider
|
|
1460
|
+
* when the stream is first consumed, which is after the credential await, so a
|
|
1461
|
+
* mutated collection would let a request that started under one configuration
|
|
1462
|
+
* finish under another — or fail with a provider that no longer exists. This is
|
|
1463
|
+
* what makes the seam's per-step call freeze (`llm.prepareCall()`) hold all the
|
|
1464
|
+
* way down: switching models mid-reply takes effect on the next step, never
|
|
1465
|
+
* inside the one in flight.
|
|
1202
1466
|
*
|
|
1203
|
-
*
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
*
|
|
1207
|
-
*
|
|
1208
|
-
*
|
|
1209
|
-
*
|
|
1467
|
+
* A route naming a credential reference still resolves it through the harness
|
|
1468
|
+
* seam and passes it as the request's `apiKey` option, which pi-ai treats as
|
|
1469
|
+
* the highest-priority auth override — that is what keeps the fail-loud
|
|
1470
|
+
* reference semantics. Everything that override does not cover reaches pi-ai
|
|
1471
|
+
* through the collection's own auth: the credential store holds the records a
|
|
1472
|
+
* login wrote and a refresh rotates, and the auth context answers the ambient
|
|
1473
|
+
* questions a provider asks while resolving. Both are stable across snapshots,
|
|
1474
|
+
* so a configuration change rebuilds the collection without forgetting who is
|
|
1475
|
+
* signed in.
|
|
1210
1476
|
*
|
|
1211
|
-
*
|
|
1212
|
-
* actually reaches for today, each completely describable with a key, an
|
|
1213
|
-
* endpoint, and headers. Bedrock signs with SigV4 over AWS credentials and a
|
|
1214
|
-
* region, Vertex needs a project, a location, and application-default
|
|
1215
|
-
* credentials, Azure needs provider environment plus an api-version, and Codex
|
|
1216
|
-
* authenticates through OAuth — none of which this configuration shape can
|
|
1217
|
-
* express, so offering them would hand back a provider that cannot
|
|
1218
|
-
* authenticate. The remainder are absent for want of a consumer rather than a
|
|
1219
|
-
* blocker: each is one line here once a deployment needs it. Catalog routes
|
|
1220
|
-
* still reach every protocol through their own provider; only an explicit
|
|
1221
|
-
* override is refused.
|
|
1477
|
+
* @module nomix-llm-pi-ai/adapter
|
|
1222
1478
|
*/
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1479
|
+
var __addDisposableResource = function(env, value, async) {
|
|
1480
|
+
if (value !== null && value !== void 0) {
|
|
1481
|
+
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
1482
|
+
var dispose, inner;
|
|
1483
|
+
if (async) {
|
|
1484
|
+
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
1485
|
+
dispose = value[Symbol.asyncDispose];
|
|
1486
|
+
}
|
|
1487
|
+
if (dispose === void 0) {
|
|
1488
|
+
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
1489
|
+
dispose = value[Symbol.dispose];
|
|
1490
|
+
if (async) inner = dispose;
|
|
1491
|
+
}
|
|
1492
|
+
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
1493
|
+
if (inner) dispose = function() {
|
|
1494
|
+
try {
|
|
1495
|
+
inner.call(this);
|
|
1496
|
+
} catch (e) {
|
|
1497
|
+
return Promise.reject(e);
|
|
1498
|
+
}
|
|
1499
|
+
};
|
|
1500
|
+
env.stack.push({
|
|
1501
|
+
value,
|
|
1502
|
+
dispose,
|
|
1503
|
+
async
|
|
1504
|
+
});
|
|
1505
|
+
} else if (async) env.stack.push({ async: true });
|
|
1506
|
+
return value;
|
|
1227
1507
|
};
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1508
|
+
var __disposeResources = (function(SuppressedError) {
|
|
1509
|
+
return function(env) {
|
|
1510
|
+
function fail(e) {
|
|
1511
|
+
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
1512
|
+
env.hasError = true;
|
|
1513
|
+
}
|
|
1514
|
+
var r, s = 0;
|
|
1515
|
+
function next() {
|
|
1516
|
+
while (r = env.stack.pop()) try {
|
|
1517
|
+
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
|
|
1518
|
+
if (r.dispose) {
|
|
1519
|
+
var result = r.dispose.call(r.value);
|
|
1520
|
+
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) {
|
|
1521
|
+
fail(e);
|
|
1522
|
+
return next();
|
|
1523
|
+
});
|
|
1524
|
+
} else s |= 1;
|
|
1525
|
+
} catch (e) {
|
|
1526
|
+
fail(e);
|
|
1527
|
+
}
|
|
1528
|
+
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
|
|
1529
|
+
if (env.hasError) throw env.error;
|
|
1530
|
+
}
|
|
1531
|
+
return next();
|
|
1532
|
+
};
|
|
1533
|
+
})(typeof SuppressedError === "function" ? SuppressedError : function(error, suppressed, message) {
|
|
1534
|
+
var e = new Error(message);
|
|
1535
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
1536
|
+
});
|
|
1537
|
+
/** Copy profile stream knobs into pi-ai's common option vocabulary. */
|
|
1538
|
+
function profileOptions(profile, reasoning, apiKey) {
|
|
1539
|
+
const enabledReasoning = reasoning === "off" ? void 0 : reasoning;
|
|
1540
|
+
return {
|
|
1541
|
+
...apiKey === void 0 ? {} : { apiKey },
|
|
1542
|
+
...enabledReasoning === void 0 ? {} : { reasoning: enabledReasoning },
|
|
1543
|
+
...profile.thinkingBudgets === void 0 ? {} : { thinkingBudgets: profile.thinkingBudgets },
|
|
1544
|
+
...profile.cacheRetention === void 0 ? {} : { cacheRetention: profile.cacheRetention },
|
|
1545
|
+
...profile.transport === void 0 ? {} : { transport: profile.transport },
|
|
1546
|
+
...profile.timeoutMs === void 0 ? {} : { timeoutMs: profile.timeoutMs },
|
|
1547
|
+
...profile.websocketConnectTimeoutMs === void 0 ? {} : { websocketConnectTimeoutMs: profile.websocketConnectTimeoutMs },
|
|
1548
|
+
maxRetries: 0
|
|
1549
|
+
};
|
|
1238
1550
|
}
|
|
1239
1551
|
/**
|
|
1240
|
-
*
|
|
1241
|
-
*
|
|
1242
|
-
*
|
|
1243
|
-
*
|
|
1244
|
-
*
|
|
1245
|
-
*
|
|
1246
|
-
*
|
|
1247
|
-
*
|
|
1248
|
-
* @param
|
|
1249
|
-
* @
|
|
1552
|
+
* The profile default this exact model can actually take, for DESCRIBING it.
|
|
1553
|
+
* A configured level the model does not support yields none rather than
|
|
1554
|
+
* throwing: `resolveModel` builds the model catalog, and a catalog that fails
|
|
1555
|
+
* takes its whole provider out of every picker — so one mis-set profile field
|
|
1556
|
+
* would hide every model on the route, including the ones that support the
|
|
1557
|
+
* level. The request path still refuses, which is where a bad configuration
|
|
1558
|
+
* belongs: describing what a model can do must not fail because a deployment
|
|
1559
|
+
* asked it for something it cannot.
|
|
1560
|
+
* @param model - the resolved model descriptor.
|
|
1561
|
+
* @param effort - the profile's configured level, if any.
|
|
1562
|
+
* @returns the level when this model supports it, otherwise undefined.
|
|
1250
1563
|
*/
|
|
1251
|
-
function
|
|
1252
|
-
return
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1564
|
+
function describableReasoningLevel(model, effort) {
|
|
1565
|
+
if (effort === void 0) return void 0;
|
|
1566
|
+
return getSupportedThinkingLevels(model).some((level) => level === effort) ? effort : void 0;
|
|
1567
|
+
}
|
|
1568
|
+
/** Validate an explicit Harness/profile effort without invoking pi-ai's clamp. */
|
|
1569
|
+
function resolveReasoningLevel(model, effort) {
|
|
1570
|
+
if (effort === void 0) return void 0;
|
|
1571
|
+
if (getSupportedThinkingLevels(model).some((level) => level === effort)) return effort;
|
|
1572
|
+
throw new LlmError(`pi-ai provider "${model.provider}" model "${model.id}" does not support reasoning effort "${effort}"`, "UNSUPPORTED_REASONING_EFFORT");
|
|
1259
1573
|
}
|
|
1260
1574
|
/**
|
|
1261
|
-
*
|
|
1262
|
-
*
|
|
1263
|
-
* A catalog route keeps the installed provider's own auth, which is what
|
|
1264
|
-
* preserves provider-native ambient discovery for a profile naming no
|
|
1265
|
-
* credential. That holds even when the profile repoints the protocol: which
|
|
1266
|
-
* environment a provider reads is a property of the provider, not of the wire
|
|
1267
|
-
* format its models speak.
|
|
1575
|
+
* Selectable reasoning efforts for one model, or nothing at all.
|
|
1268
1576
|
*
|
|
1269
|
-
*
|
|
1270
|
-
*
|
|
1271
|
-
*
|
|
1272
|
-
*
|
|
1273
|
-
*
|
|
1274
|
-
*
|
|
1275
|
-
*
|
|
1276
|
-
*
|
|
1277
|
-
*
|
|
1278
|
-
* @param
|
|
1279
|
-
* @param
|
|
1280
|
-
* @returns the
|
|
1577
|
+
* A model that carries no reasoning metadata — every hand-declared one, and
|
|
1578
|
+
* every catalog model pi-ai marks as non-reasoning — is reported by pi-ai as
|
|
1579
|
+
* supporting the single level `off`. Passing that through would offer a control
|
|
1580
|
+
* that cannot do what it says: `off` is translated to *omitting* the reasoning
|
|
1581
|
+
* option, which for such a model is byte-for-byte the same request as naming no
|
|
1582
|
+
* effort — so a provider whose own default is to think would keep thinking with
|
|
1583
|
+
* `off` selected. Omitting `reasoning` entirely is the seam's way of saying the
|
|
1584
|
+
* capability is unavailable, which leaves the surface offering only the
|
|
1585
|
+
* provider's default.
|
|
1586
|
+
* @param model - the resolved model descriptor.
|
|
1587
|
+
* @param defaultLevel - the profile's configured effort, already validated.
|
|
1588
|
+
* @returns the `reasoning` field, or an empty object when none can be offered.
|
|
1281
1589
|
*/
|
|
1282
|
-
function
|
|
1283
|
-
if (
|
|
1284
|
-
|
|
1590
|
+
function reasoningInfo(model, defaultLevel) {
|
|
1591
|
+
if (!model.reasoning) return {};
|
|
1592
|
+
return { reasoning: {
|
|
1593
|
+
efforts: getSupportedThinkingLevels(model).map((level) => ({
|
|
1594
|
+
id: ReasoningEffortId(level),
|
|
1595
|
+
name: `${level.charAt(0).toUpperCase()}${level.slice(1)}`
|
|
1596
|
+
})),
|
|
1597
|
+
...defaultLevel === void 0 ? {} : { defaultEffort: ReasoningEffortId(defaultLevel) }
|
|
1598
|
+
} };
|
|
1599
|
+
}
|
|
1600
|
+
/** Merge deployment headers while removing case-insensitive attribution collisions. */
|
|
1601
|
+
function requestHeaders(headers) {
|
|
1602
|
+
const attribution = attributionHeaders();
|
|
1603
|
+
const reserved = new Set(Object.keys(attribution).map((name) => name.toLowerCase()));
|
|
1285
1604
|
return {
|
|
1286
|
-
...
|
|
1287
|
-
|
|
1605
|
+
...Object.fromEntries(Object.entries(headers ?? {}).filter(([name]) => !reserved.has(name.toLowerCase()))),
|
|
1606
|
+
...attribution
|
|
1288
1607
|
};
|
|
1289
1608
|
}
|
|
1290
1609
|
/**
|
|
1291
|
-
*
|
|
1292
|
-
*
|
|
1293
|
-
*
|
|
1294
|
-
* Catalog-owned dynamic refresh is dropped: this route's catalog is the
|
|
1295
|
-
* settings document, and a background refresh would contradict it.
|
|
1610
|
+
* pi-ai-backed multi-provider adapter. Each operation reads the current
|
|
1611
|
+
* profiles, so a configuration change reaches the next request without a
|
|
1612
|
+
* restart; model descriptors come from the collection those profiles built.
|
|
1296
1613
|
*/
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1614
|
+
var PiAiAdapter = class extends LlmAdapter {
|
|
1615
|
+
config;
|
|
1616
|
+
snapshot;
|
|
1617
|
+
constructor(config) {
|
|
1618
|
+
super();
|
|
1619
|
+
this.config = config;
|
|
1620
|
+
}
|
|
1621
|
+
/**
|
|
1622
|
+
* The snapshot for the current profiles. Resolution memoizes its result, so
|
|
1623
|
+
* an unchanged configuration is recognized by identity; a changed one gets a
|
|
1624
|
+
* brand-new collection, leaving any snapshot an operation already captured
|
|
1625
|
+
* untouched for as long as that operation holds it.
|
|
1626
|
+
*/
|
|
1627
|
+
current() {
|
|
1628
|
+
const profiles = this.config.profiles();
|
|
1629
|
+
if (this.snapshot?.profiles === profiles) return this.snapshot;
|
|
1630
|
+
const models = createModels(this.config.auth);
|
|
1631
|
+
for (const profile of profiles.values()) models.setProvider(profile.piProvider);
|
|
1632
|
+
this.snapshot = {
|
|
1633
|
+
profiles,
|
|
1634
|
+
models
|
|
1635
|
+
};
|
|
1636
|
+
return this.snapshot;
|
|
1637
|
+
}
|
|
1638
|
+
/** The profile for one route within one snapshot, or the not-owned failure. */
|
|
1639
|
+
profileOf(snapshot, provider) {
|
|
1640
|
+
const profile = snapshot.profiles.get(provider);
|
|
1641
|
+
if (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider "${provider}"`, "NO_ADAPTER");
|
|
1642
|
+
return profile;
|
|
1643
|
+
}
|
|
1644
|
+
/** The configured descriptor for one exact route/model pair within one snapshot. */
|
|
1645
|
+
modelOf(snapshot, provider, model) {
|
|
1646
|
+
this.profileOf(snapshot, provider);
|
|
1647
|
+
const resolved = snapshot.models.getModel(provider, model);
|
|
1648
|
+
if (resolved === void 0) throw new LlmError(`pi-ai provider "${provider}" has no configured model "${model}"`, "UNKNOWN_MODEL");
|
|
1649
|
+
return resolved;
|
|
1650
|
+
}
|
|
1651
|
+
providerInfo(provider) {
|
|
1652
|
+
return {
|
|
1653
|
+
id: provider,
|
|
1654
|
+
name: this.current().profiles.get(provider)?.displayName ?? provider
|
|
1655
|
+
};
|
|
1656
|
+
}
|
|
1657
|
+
providerRetryPolicy(provider) {
|
|
1658
|
+
return this.current().profiles.get(provider)?.retryPolicy;
|
|
1659
|
+
}
|
|
1660
|
+
listModels(provider) {
|
|
1661
|
+
return Promise.resolve().then(() => {
|
|
1662
|
+
const snapshot = this.current();
|
|
1663
|
+
this.profileOf(snapshot, provider);
|
|
1664
|
+
return snapshot.models.getModels(provider).map((model) => ({
|
|
1665
|
+
provider,
|
|
1666
|
+
id: model.id,
|
|
1667
|
+
name: model.name,
|
|
1668
|
+
inputModalities: [...model.input]
|
|
1669
|
+
}));
|
|
1670
|
+
});
|
|
1671
|
+
}
|
|
1672
|
+
resolveModel(provider, model, _signal) {
|
|
1673
|
+
return Promise.resolve().then(() => {
|
|
1674
|
+
const snapshot = this.current();
|
|
1675
|
+
return this.modelInfo(snapshot, provider, model);
|
|
1676
|
+
});
|
|
1677
|
+
}
|
|
1678
|
+
modelInfo(snapshot, provider, model) {
|
|
1679
|
+
const profile = this.profileOf(snapshot, provider);
|
|
1680
|
+
const resolvedModel = this.modelOf(snapshot, provider, model);
|
|
1681
|
+
const defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);
|
|
1682
|
+
const configuredMaxTokens = profile.configuredMaxTokens.get(model);
|
|
1683
|
+
return {
|
|
1684
|
+
provider,
|
|
1685
|
+
id: model,
|
|
1686
|
+
name: resolvedModel.name,
|
|
1687
|
+
inputModalities: [...resolvedModel.input],
|
|
1688
|
+
context: { contextWindow: resolvedModel.contextWindow },
|
|
1689
|
+
...configuredMaxTokens === void 0 ? {} : { defaultMaxTokens: configuredMaxTokens },
|
|
1690
|
+
...reasoningInfo(resolvedModel, defaultLevel)
|
|
1691
|
+
};
|
|
1692
|
+
}
|
|
1693
|
+
prepareCall(provider, model, _signal) {
|
|
1694
|
+
const snapshot = this.current();
|
|
1695
|
+
return Promise.resolve({
|
|
1696
|
+
model: this.modelInfo(snapshot, provider, model),
|
|
1697
|
+
stream: (options) => this.streamWithSnapshot(options, snapshot)
|
|
1698
|
+
});
|
|
1699
|
+
}
|
|
1700
|
+
stream(options) {
|
|
1701
|
+
return this.streamWithSnapshot(options, this.current());
|
|
1702
|
+
}
|
|
1703
|
+
async *streamWithSnapshot(options, snapshot) {
|
|
1704
|
+
const env_1 = {
|
|
1705
|
+
stack: [],
|
|
1706
|
+
error: void 0,
|
|
1707
|
+
hasError: false
|
|
1708
|
+
};
|
|
1709
|
+
try {
|
|
1710
|
+
if (options.stop !== void 0) throw new LlmError("llm-pi-ai does not support GenerateOptions.stop", "UNSUPPORTED_OPTION");
|
|
1711
|
+
const profile = this.profileOf(snapshot, options.provider);
|
|
1712
|
+
const model = this.modelOf(snapshot, options.provider, options.model);
|
|
1713
|
+
const reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);
|
|
1714
|
+
const apiKey = await this.config.resolveApiKey(options.provider, profile);
|
|
1715
|
+
const consumer = new AbortController();
|
|
1716
|
+
const upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);
|
|
1717
|
+
const streamIdleTimeoutMs = profile.streamIdleTimeoutMs;
|
|
1718
|
+
const watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, "LLM_STREAM_IDLE_TIMEOUT"), false);
|
|
1719
|
+
try {
|
|
1720
|
+
const containsImage = options.messages.some((message) => contentHasImage(message.content));
|
|
1721
|
+
if (containsImage && !model.input.includes("image")) throw new LlmError(`pi-ai model "${model.id}" does not support image input`, "UNSUPPORTED_CONTENT");
|
|
1722
|
+
const attachments = containsImage ? this.config.resolveAttachments?.() : void 0;
|
|
1723
|
+
if (containsImage && attachments === void 0) throw new LlmError("pi-ai image input requires the durable attachment service", "UNSUPPORTED_CONTENT");
|
|
1724
|
+
const onReplayDegrade = (reason) => {
|
|
1725
|
+
this.config.onReplayDegrade?.({
|
|
1726
|
+
provider: options.provider,
|
|
1727
|
+
model: options.model,
|
|
1728
|
+
reason
|
|
1729
|
+
});
|
|
1730
|
+
};
|
|
1731
|
+
const context = attachments === void 0 ? toPiContext(options, void 0, onReplayDegrade) : await toPiContext({
|
|
1732
|
+
...options,
|
|
1733
|
+
signal: watchdog.signal
|
|
1734
|
+
}, attachments, onReplayDegrade, profile.maxRequestImageBytes, {
|
|
1735
|
+
maxPixels: profile.requestImagePixelBudget,
|
|
1736
|
+
maxBytes: profile.requestImageMaxBytes
|
|
1737
|
+
});
|
|
1738
|
+
const iterator = toStreamChunks(snapshot.models.streamSimple(model, context, {
|
|
1739
|
+
...profileOptions(profile, reasoning, apiKey),
|
|
1740
|
+
...options.temperature === void 0 ? {} : { temperature: options.temperature },
|
|
1741
|
+
...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },
|
|
1742
|
+
...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },
|
|
1743
|
+
signal: watchdog.signal,
|
|
1744
|
+
headers: requestHeaders(profile.headers)
|
|
1745
|
+
}), model.contextWindow)[Symbol.asyncIterator]();
|
|
1746
|
+
let exhausted = false;
|
|
1747
|
+
try {
|
|
1748
|
+
while (true) {
|
|
1749
|
+
const result = await watchdog.next(iterator);
|
|
1750
|
+
const timeout = timeoutOf(watchdog.signal, "LLM_STREAM_IDLE_TIMEOUT");
|
|
1751
|
+
if (timeout !== void 0) throw timeout;
|
|
1752
|
+
if (result.done) {
|
|
1753
|
+
exhausted = true;
|
|
1754
|
+
return;
|
|
1755
|
+
}
|
|
1756
|
+
yield result.value;
|
|
1757
|
+
}
|
|
1758
|
+
} finally {
|
|
1759
|
+
if (!exhausted) {
|
|
1760
|
+
consumer.abort("pi-ai stream consumer stopped");
|
|
1761
|
+
try {
|
|
1762
|
+
await iterator.return(void 0);
|
|
1763
|
+
} catch (_abortedSdkTeardown) {}
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
} catch (error) {
|
|
1767
|
+
if (timeoutOf(watchdog.signal, "LLM_STREAM_IDLE_TIMEOUT") !== void 0) throw new LlmError(`pi-ai stream idle timeout after ${streamIdleTimeoutMs}ms`, "TIMEOUT", { cause: error });
|
|
1768
|
+
if (options.signal?.aborted) throw new LlmError("pi-ai request aborted by caller", "ABORTED", { cause: error });
|
|
1769
|
+
throw error;
|
|
1770
|
+
} finally {
|
|
1771
|
+
consumer.abort("pi-ai stream consumer stopped");
|
|
1772
|
+
}
|
|
1773
|
+
} catch (e_1) {
|
|
1774
|
+
env_1.error = e_1;
|
|
1775
|
+
env_1.hasError = true;
|
|
1776
|
+
} finally {
|
|
1777
|
+
__disposeResources(env_1);
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1780
|
+
};
|
|
1781
|
+
//#endregion
|
|
1782
|
+
//#region lib/types/auth.js
|
|
1309
1783
|
/**
|
|
1310
|
-
*
|
|
1311
|
-
*
|
|
1312
|
-
*
|
|
1313
|
-
*
|
|
1784
|
+
* The three adapters between pi-ai's auth model and the harness credential
|
|
1785
|
+
* plane. Every pi-ai-specific concept stays on this side of them: the harness
|
|
1786
|
+
* seams they consume — `ctx.credentials` records and `ctx.authorization` flows —
|
|
1787
|
+
* name nothing from this library, so another adapter family can arrive with a
|
|
1788
|
+
* different auth model and share the same two seams.
|
|
1789
|
+
*
|
|
1790
|
+
* @module nomix-llm-pi-ai/auth
|
|
1314
1791
|
*/
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1792
|
+
/**
|
|
1793
|
+
* The record scope every credential this adapter family stores is written
|
|
1794
|
+
* under. It is the plugin's registered name, which is what tells a later
|
|
1795
|
+
* reader — a configuration UI, or a second adapter family serving the same
|
|
1796
|
+
* provider name — that this plugin owns the format inside the record.
|
|
1797
|
+
*/
|
|
1798
|
+
const RECORD_SCOPE = "llm-pi-ai";
|
|
1799
|
+
/**
|
|
1800
|
+
* The record address for one pi-ai provider id.
|
|
1801
|
+
* @param providerId - pi-ai's own provider id, which is also the harness route key.
|
|
1802
|
+
* @returns the scoped credential key this adapter family reads and writes.
|
|
1803
|
+
*/
|
|
1804
|
+
function recordKeyFor(providerId) {
|
|
1805
|
+
return credentialKey(RECORD_SCOPE, providerId);
|
|
1328
1806
|
}
|
|
1329
|
-
//#endregion
|
|
1330
|
-
//#region lib/types/config.js
|
|
1331
1807
|
/**
|
|
1332
|
-
*
|
|
1333
|
-
* Profiles are a dict keyed by provider route, so the composition base and a
|
|
1334
|
-
* user-settings layer merge per provider and the route set is structural.
|
|
1335
|
-
*
|
|
1336
|
-
* A route key is not required to name an installed pi-ai provider. When it does,
|
|
1337
|
-
* that provider's endpoint, protocol, display name, and model catalog are the
|
|
1338
|
-
* profile's defaults and the profile overrides them field by field; when it does
|
|
1339
|
-
* not, the profile is the whole provider declaration. Resolution therefore ends
|
|
1340
|
-
* in a built pi-ai `Provider` per route: everything a request needs is decided
|
|
1341
|
-
* once, while the configuration key that made a route unserviceable can still be
|
|
1342
|
-
* named in the failure.
|
|
1808
|
+
* Translate a stored record into the credential pi-ai expects.
|
|
1343
1809
|
*
|
|
1344
|
-
*
|
|
1810
|
+
* An `api-key` record is structural on both sides, so it is rebuilt field by
|
|
1811
|
+
* field. A `grant` payload is pi-ai's own OAuth credential, stored verbatim:
|
|
1812
|
+
* the seam treats it as opaque JSON precisely so a library that owns a token
|
|
1813
|
+
* format keeps owning it, refresh fields and all.
|
|
1814
|
+
* @param record - the stored record, or undefined when nothing is stored.
|
|
1815
|
+
* @returns the pi-ai credential, or undefined for an absent record.
|
|
1345
1816
|
*/
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1817
|
+
function toPiCredential(record) {
|
|
1818
|
+
if (record === void 0) return void 0;
|
|
1819
|
+
if (record.kind === "api-key") return {
|
|
1820
|
+
type: "api_key",
|
|
1821
|
+
...record.key === void 0 ? {} : { key: record.key },
|
|
1822
|
+
...record.env === void 0 ? {} : { env: { ...record.env } }
|
|
1823
|
+
};
|
|
1824
|
+
return record.payload;
|
|
1825
|
+
}
|
|
1352
1826
|
/**
|
|
1353
|
-
*
|
|
1354
|
-
*
|
|
1355
|
-
*
|
|
1356
|
-
* nothing can interrogate a gateway for its modalities, and the two wrong
|
|
1357
|
-
* answers do not cost the same. Under-claiming refuses the image before it is
|
|
1358
|
-
* attached, naming the model. Over-claiming admits one the provider then
|
|
1359
|
-
* rejects mid-turn, after the message is durable, leaving the session
|
|
1360
|
-
* repeating a request that cannot succeed.
|
|
1827
|
+
* Translate a pi-ai credential into the record to store.
|
|
1828
|
+
* @param credential - what a login or refresh produced.
|
|
1829
|
+
* @returns the record to commit, in the union the credential seam stores.
|
|
1361
1830
|
*/
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
}
|
|
1831
|
+
function toRecord(credential) {
|
|
1832
|
+
if (credential.type === "api_key") return {
|
|
1833
|
+
kind: "api-key",
|
|
1834
|
+
...credential.key === void 0 ? {} : { key: credential.key },
|
|
1835
|
+
...credential.env === void 0 ? {} : { env: { ...credential.env } }
|
|
1836
|
+
};
|
|
1837
|
+
return {
|
|
1838
|
+
kind: "grant",
|
|
1839
|
+
payload: credential
|
|
1840
|
+
};
|
|
1841
|
+
}
|
|
1373
1842
|
/**
|
|
1374
|
-
*
|
|
1375
|
-
*
|
|
1376
|
-
*
|
|
1377
|
-
*
|
|
1378
|
-
*
|
|
1379
|
-
*
|
|
1380
|
-
*
|
|
1381
|
-
*
|
|
1843
|
+
* The credential service, or the failure that names what is missing. Reads
|
|
1844
|
+
* answer "nothing stored" without a service, because a composition with no
|
|
1845
|
+
* credential plane genuinely holds no credential; writes refuse, because a
|
|
1846
|
+
* login whose grant silently evaporated would report success and then fail
|
|
1847
|
+
* every request.
|
|
1848
|
+
* @param ctx - the plugin context.
|
|
1849
|
+
* @returns the live service.
|
|
1850
|
+
* @throws {LlmError} code `NO_CREDENTIAL_STORE` when none is mounted.
|
|
1382
1851
|
*/
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
maxTokens: z.number().step(1).min(1),
|
|
1389
|
-
input: z.array(z.union(MODALITIES)),
|
|
1390
|
-
reasoningEfforts: z.union([z.const(false), reasoningEfforts]),
|
|
1391
|
-
compat: compatProfile
|
|
1392
|
-
};
|
|
1393
|
-
const modelProfile = z.object({
|
|
1394
|
-
id: z.string().required(),
|
|
1395
|
-
...modelFields
|
|
1396
|
-
});
|
|
1397
|
-
/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */
|
|
1398
|
-
const modelOverride = z.object(modelFields);
|
|
1399
|
-
const profile = z.object({
|
|
1400
|
-
apiKeyEnv: z.string().role("credential-ref"),
|
|
1401
|
-
displayName: z.string(),
|
|
1402
|
-
api: z.union(supportedProtocols()),
|
|
1403
|
-
baseURL: z.string(),
|
|
1404
|
-
models: z.array(modelProfile),
|
|
1405
|
-
modelOverrides: z.dict(modelOverride),
|
|
1406
|
-
compat: compatProfile,
|
|
1407
|
-
defaultContextWindow: z.number().step(1).min(1).default(DEFAULT_CONTEXT_WINDOW),
|
|
1408
|
-
defaultMaxTokens: z.number().step(1).min(1).default(DEFAULT_MAX_TOKENS),
|
|
1409
|
-
defaultInput: z.array(z.union(MODALITIES)).default([...DEFAULT_INPUT]),
|
|
1410
|
-
headers: z.dict(z.string()),
|
|
1411
|
-
reasoning: z.union(THINKING_LEVELS),
|
|
1412
|
-
thinkingBudgets,
|
|
1413
|
-
cacheRetention: z.union([
|
|
1414
|
-
"none",
|
|
1415
|
-
"short",
|
|
1416
|
-
"long"
|
|
1417
|
-
]),
|
|
1418
|
-
transport: z.union([
|
|
1419
|
-
"sse",
|
|
1420
|
-
"websocket",
|
|
1421
|
-
"websocket-cached",
|
|
1422
|
-
"auto"
|
|
1423
|
-
]),
|
|
1424
|
-
timeoutMs: z.natural(),
|
|
1425
|
-
websocketConnectTimeoutMs: z.natural(),
|
|
1426
|
-
streamIdleTimeoutMs: z.number().min(Number.MIN_VALUE).max(MAX_TIMER_DELAY_MS).default(DEFAULT_STREAM_IDLE_TIMEOUT_MS),
|
|
1427
|
-
retryPolicy: RetryPolicySchema
|
|
1428
|
-
});
|
|
1429
|
-
/** Runtime schema for {@link Config}. */
|
|
1430
|
-
const Config = z.object({ providers: z.dict(profile).default({}) });
|
|
1852
|
+
function writableStore(ctx) {
|
|
1853
|
+
const credentials = ctx.get("credentials");
|
|
1854
|
+
if (credentials === void 0) throw new LlmError("llm-pi-ai: this composition mounts no credentials service, so there is nowhere to store the credential a sign-in produces; mount one (nomix-credentials-local) to sign in", "NO_CREDENTIAL_STORE");
|
|
1855
|
+
return credentials;
|
|
1856
|
+
}
|
|
1431
1857
|
/**
|
|
1432
|
-
*
|
|
1433
|
-
*
|
|
1434
|
-
* *
|
|
1435
|
-
*
|
|
1436
|
-
*
|
|
1437
|
-
*
|
|
1438
|
-
*
|
|
1439
|
-
*
|
|
1440
|
-
*
|
|
1441
|
-
*
|
|
1858
|
+
* A pi-ai `CredentialStore` over the harness credential records.
|
|
1859
|
+
*
|
|
1860
|
+
* pi-ai runs OAuth refresh *inside* `modify()`, so this store's exclusion has
|
|
1861
|
+
* to cover a network round trip rather than a file rename — which is why the
|
|
1862
|
+
* record write path takes a wait limit of its own rather than the short one a
|
|
1863
|
+
* local write would need.
|
|
1864
|
+
*
|
|
1865
|
+
* pi-ai asks this store about every provider in the collection, hand-declared
|
|
1866
|
+
* routes included, and a route key is an arbitrary settings dict key while a
|
|
1867
|
+
* record id is not. An id outside the record grammar can never have stored a
|
|
1868
|
+
* record, so reads answer "nothing stored" and a delete has nothing to remove;
|
|
1869
|
+
* only `modify` refuses it, because a write that cannot land must not report
|
|
1870
|
+
* that it did.
|
|
1871
|
+
* @param ctx - the plugin context carrying the optional `ctx.credentials`.
|
|
1872
|
+
* @returns the store to hand `createModels()`.
|
|
1442
1873
|
*/
|
|
1443
|
-
function
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1874
|
+
function credentialStoreFrom(ctx) {
|
|
1875
|
+
return {
|
|
1876
|
+
async read(providerId) {
|
|
1877
|
+
const credentials = ctx.get("credentials");
|
|
1878
|
+
if (credentials === void 0) return void 0;
|
|
1879
|
+
if (!isCredentialKeySegment(providerId)) return void 0;
|
|
1880
|
+
return toPiCredential(await credentials.readRecord(recordKeyFor(providerId)));
|
|
1881
|
+
},
|
|
1882
|
+
async list() {
|
|
1883
|
+
const stored = await ctx.get("credentials")?.listRecords() ?? [];
|
|
1884
|
+
const mine = [];
|
|
1885
|
+
for (const entry of stored) {
|
|
1886
|
+
if (credentialKeyScope(entry.key) !== "llm-pi-ai") continue;
|
|
1887
|
+
mine.push({
|
|
1888
|
+
providerId: credentialKeyId(entry.key),
|
|
1889
|
+
type: entry.kind === "api-key" ? "api_key" : "oauth"
|
|
1890
|
+
});
|
|
1891
|
+
}
|
|
1892
|
+
return mine;
|
|
1893
|
+
},
|
|
1894
|
+
async modify(providerId, mutate) {
|
|
1895
|
+
if (!isCredentialKeySegment(providerId)) throw new LlmError(`llm-pi-ai: provider id "${providerId}" cannot address a stored credential record (a record id is a lowercase hyphenated identifier); authenticate this route through apiKeyEnv instead of a stored credential`, "UNSTORABLE_PROVIDER_ID");
|
|
1896
|
+
return toPiCredential(await writableStore(ctx).modifyRecord(recordKeyFor(providerId), async (current) => {
|
|
1897
|
+
const next = await mutate(toPiCredential(current));
|
|
1898
|
+
return next === void 0 ? void 0 : toRecord(next);
|
|
1899
|
+
}));
|
|
1900
|
+
},
|
|
1901
|
+
async delete(providerId) {
|
|
1902
|
+
if (!isCredentialKeySegment(providerId)) return;
|
|
1903
|
+
await writableStore(ctx).deleteRecord(recordKeyFor(providerId));
|
|
1904
|
+
}
|
|
1905
|
+
};
|
|
1451
1906
|
}
|
|
1452
1907
|
/**
|
|
1453
|
-
*
|
|
1454
|
-
*
|
|
1455
|
-
*
|
|
1456
|
-
*
|
|
1457
|
-
*
|
|
1458
|
-
*
|
|
1908
|
+
* A pi-ai `AuthContext` over the harness credential plane and the host
|
|
1909
|
+
* filesystem.
|
|
1910
|
+
*
|
|
1911
|
+
* `env()` answers from the credential seam first, so a value a deployment
|
|
1912
|
+
* stored through the harness is found by a provider's own ambient discovery —
|
|
1913
|
+
* without this, that discovery reads only the process environment and a stored
|
|
1914
|
+
* `AWS_ACCESS_KEY_ID` is invisible to it. `fileExists()` answers about the host
|
|
1915
|
+
* process's own filesystem rather than the workspace `ctx.fs` seam, because the
|
|
1916
|
+
* paths it is asked about (`~/.aws/credentials`, application-default
|
|
1917
|
+
* credentials) are facts about where this process runs, not about the project
|
|
1918
|
+
* under edit.
|
|
1919
|
+
* @param ctx - the plugin context carrying the optional `ctx.credentials`.
|
|
1920
|
+
* @returns the auth context to hand `createModels()`.
|
|
1459
1921
|
*/
|
|
1460
|
-
function
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
...source.modelOverrides === void 0 ? {} : { modelOverrides: source.modelOverrides },
|
|
1480
|
-
...source.compat === void 0 ? {} : { compat: source.compat },
|
|
1481
|
-
defaultInput,
|
|
1482
|
-
defaultContextWindow: source.defaultContextWindow ?? 262144,
|
|
1483
|
-
defaultMaxTokens: source.defaultMaxTokens ?? 32768
|
|
1484
|
-
});
|
|
1485
|
-
const { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, ...rest } = source;
|
|
1486
|
-
resolved.set(provider, {
|
|
1487
|
-
...rest,
|
|
1488
|
-
provider,
|
|
1489
|
-
displayName,
|
|
1490
|
-
...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },
|
|
1491
|
-
streamIdleTimeoutMs,
|
|
1492
|
-
retryPolicy: resolveRetryPolicy(retryPolicy, `llm-pi-ai: provider "${provider}" retryPolicy`),
|
|
1493
|
-
...rest.headers === void 0 ? {} : { headers: { ...rest.headers } },
|
|
1494
|
-
...rest.thinkingBudgets === void 0 ? {} : { thinkingBudgets: { ...rest.thinkingBudgets } },
|
|
1495
|
-
configuredMaxTokens: catalog.configuredMaxTokens,
|
|
1496
|
-
piProvider: buildProvider({
|
|
1497
|
-
provider,
|
|
1498
|
-
displayName,
|
|
1499
|
-
...source.api === void 0 ? {} : { api: source.api },
|
|
1500
|
-
...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },
|
|
1501
|
-
models: catalog.models,
|
|
1502
|
-
namesCredential: apiKeyEnv !== void 0
|
|
1503
|
-
})
|
|
1504
|
-
});
|
|
1505
|
-
}
|
|
1506
|
-
return resolved;
|
|
1922
|
+
function authContextFrom(ctx) {
|
|
1923
|
+
return {
|
|
1924
|
+
async env(name) {
|
|
1925
|
+
if (isCredentialRefName(name)) {
|
|
1926
|
+
const hit = await ctx.get("credentials")?.resolve(credentialRef(name));
|
|
1927
|
+
if (hit !== void 0) return hit.value;
|
|
1928
|
+
}
|
|
1929
|
+
return launchEnvironmentOf(ctx).get(name)?.value;
|
|
1930
|
+
},
|
|
1931
|
+
async fileExists(path) {
|
|
1932
|
+
const expanded = path.startsWith("~/") || path === "~" ? resolve(homedir(), path.slice(1).replace(/^\//, "")) : path;
|
|
1933
|
+
try {
|
|
1934
|
+
await access(expanded);
|
|
1935
|
+
return true;
|
|
1936
|
+
} catch {
|
|
1937
|
+
return false;
|
|
1938
|
+
}
|
|
1939
|
+
}
|
|
1940
|
+
};
|
|
1507
1941
|
}
|
|
1508
1942
|
//#endregion
|
|
1509
1943
|
//#region lib/types/discovery.js
|
|
@@ -1700,6 +2134,156 @@ async function discoverModels(request, storedApiKey) {
|
|
|
1700
2134
|
return readListing(body);
|
|
1701
2135
|
}
|
|
1702
2136
|
//#endregion
|
|
2137
|
+
//#region lib/types/login.js
|
|
2138
|
+
/**
|
|
2139
|
+
* Authorization flows for the pi-ai providers that ship a login. This is the
|
|
2140
|
+
* whole of the translation between the harness's neutral notice/prompt
|
|
2141
|
+
* vocabulary and pi-ai's `AuthInteraction`; nothing above it knows which
|
|
2142
|
+
* library ran the conversation.
|
|
2143
|
+
*
|
|
2144
|
+
* @module nomix-llm-pi-ai/login
|
|
2145
|
+
*/
|
|
2146
|
+
/**
|
|
2147
|
+
* The login methods one catalog provider offers.
|
|
2148
|
+
*
|
|
2149
|
+
* A method appears only when pi-ai can actually run it: `oauth` always carries
|
|
2150
|
+
* a `login`, while an api-key method has one only when the provider collects
|
|
2151
|
+
* its key interactively — which every installed one currently does, so a key is
|
|
2152
|
+
* typed into pi-ai's own prompt rather than into the settings form.
|
|
2153
|
+
* @param provider - the installed catalog provider, if pi-ai ships one.
|
|
2154
|
+
* @returns its methods, most preferred first; empty when it offers no login.
|
|
2155
|
+
*/
|
|
2156
|
+
function loginMethods(provider) {
|
|
2157
|
+
const methods = [];
|
|
2158
|
+
const oauth = provider?.auth.oauth;
|
|
2159
|
+
if (oauth !== void 0) methods.push({
|
|
2160
|
+
id: "oauth",
|
|
2161
|
+
label: oauth.loginLabel ?? oauth.name
|
|
2162
|
+
});
|
|
2163
|
+
const apiKey = provider?.auth.apiKey;
|
|
2164
|
+
if (apiKey?.login !== void 0) methods.push({
|
|
2165
|
+
id: "api-key",
|
|
2166
|
+
label: apiKey.name
|
|
2167
|
+
});
|
|
2168
|
+
return methods;
|
|
2169
|
+
}
|
|
2170
|
+
/**
|
|
2171
|
+
* Restate one pi-ai login event in the seam's vocabulary.
|
|
2172
|
+
*
|
|
2173
|
+
* A device-code grant is the one event carrying two things the human needs at
|
|
2174
|
+
* once — where to go and what to type there — which is why the neutral notice
|
|
2175
|
+
* has a `code` beside its `url` rather than folding the code into the message.
|
|
2176
|
+
* @param event - what pi-ai reported.
|
|
2177
|
+
* @param session - the attempt to report it to.
|
|
2178
|
+
*/
|
|
2179
|
+
function relay(event, session) {
|
|
2180
|
+
switch (event.type) {
|
|
2181
|
+
case "info": {
|
|
2182
|
+
const link = event.links?.[0];
|
|
2183
|
+
session.notify({
|
|
2184
|
+
message: event.message,
|
|
2185
|
+
...link === void 0 ? {} : { url: link.url }
|
|
2186
|
+
});
|
|
2187
|
+
return;
|
|
2188
|
+
}
|
|
2189
|
+
case "auth_url":
|
|
2190
|
+
session.notify({
|
|
2191
|
+
message: event.instructions ?? "Open this page to continue signing in.",
|
|
2192
|
+
url: event.url
|
|
2193
|
+
});
|
|
2194
|
+
return;
|
|
2195
|
+
case "device_code":
|
|
2196
|
+
session.notify({
|
|
2197
|
+
message: "Enter this code on the verification page to finish signing in.",
|
|
2198
|
+
url: event.verificationUri,
|
|
2199
|
+
code: event.userCode
|
|
2200
|
+
});
|
|
2201
|
+
return;
|
|
2202
|
+
case "progress":
|
|
2203
|
+
session.notify({ message: event.message });
|
|
2204
|
+
return;
|
|
2205
|
+
default: session.notify({ message: "Signing in…" });
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
2208
|
+
/**
|
|
2209
|
+
* Restate one pi-ai prompt in the seam's vocabulary.
|
|
2210
|
+
*
|
|
2211
|
+
* `manual_code` becomes a plain text question because the difference pi-ai
|
|
2212
|
+
* draws — a code the human copies from a browser rather than a value they know
|
|
2213
|
+
* — changes nothing a surface renders. Its own `signal` is carried through, and
|
|
2214
|
+
* that is the part which matters: it is how a flow racing a typed code against
|
|
2215
|
+
* a browser callback withdraws the losing question.
|
|
2216
|
+
* @param prompt - what pi-ai asked.
|
|
2217
|
+
* @returns the neutral prompt to put to the human.
|
|
2218
|
+
*/
|
|
2219
|
+
function restate(prompt) {
|
|
2220
|
+
const signal = prompt.signal === void 0 ? {} : { signal: prompt.signal };
|
|
2221
|
+
switch (prompt.type) {
|
|
2222
|
+
case "select": return {
|
|
2223
|
+
...signal,
|
|
2224
|
+
kind: "select",
|
|
2225
|
+
message: prompt.message,
|
|
2226
|
+
options: prompt.options
|
|
2227
|
+
};
|
|
2228
|
+
case "secret": return {
|
|
2229
|
+
...signal,
|
|
2230
|
+
kind: "secret",
|
|
2231
|
+
message: prompt.message,
|
|
2232
|
+
...prompt.placeholder === void 0 ? {} : { placeholder: prompt.placeholder }
|
|
2233
|
+
};
|
|
2234
|
+
default: return {
|
|
2235
|
+
...signal,
|
|
2236
|
+
kind: "text",
|
|
2237
|
+
message: prompt.message,
|
|
2238
|
+
...prompt.placeholder === void 0 ? {} : { placeholder: prompt.placeholder }
|
|
2239
|
+
};
|
|
2240
|
+
}
|
|
2241
|
+
}
|
|
2242
|
+
/**
|
|
2243
|
+
* Register one authorization flow per installed provider that ships a login.
|
|
2244
|
+
*
|
|
2245
|
+
* Registration is unconditional on configuration: a provider has to be signed
|
|
2246
|
+
* into before a route for it is worth adding, so the flow exists from the
|
|
2247
|
+
* moment the plugin mounts rather than appearing once a profile does.
|
|
2248
|
+
* @param ctx - the plugin context carrying `ctx.authorization`.
|
|
2249
|
+
* @param auth - the injectables every collection here is built with.
|
|
2250
|
+
*/
|
|
2251
|
+
function registerPiAiFlows(ctx, auth) {
|
|
2252
|
+
for (const providerId of catalogProviderIds()) {
|
|
2253
|
+
const provider = catalogProvider(providerId);
|
|
2254
|
+
const [first, ...rest] = loginMethods(provider);
|
|
2255
|
+
/* v8 ignore next 3 -- every id here names an installed provider and every
|
|
2256
|
+
installed provider ships a login, so nothing is skipped today; the guard
|
|
2257
|
+
is what keeps that from becoming a crash if either stops being true. */
|
|
2258
|
+
if (provider === void 0 || first === void 0) continue;
|
|
2259
|
+
/* v8 ignore next 7 -- every installed catalog id today is a lowercase
|
|
2260
|
+
hyphenated identifier; the guard keeps a future upstream id outside the
|
|
2261
|
+
record grammar (dotted or uppercase, as vendor ids elsewhere already
|
|
2262
|
+
are) from throwing in `recordKeyFor` and failing the whole mount. */
|
|
2263
|
+
if (!isCredentialKeySegment(providerId)) {
|
|
2264
|
+
ctx.logger.warn("llm-pi-ai: catalog provider \"%s\" cannot address a credential record; its sign-in is not offered", providerId);
|
|
2265
|
+
continue;
|
|
2266
|
+
}
|
|
2267
|
+
ctx.authorization.registerFlow({
|
|
2268
|
+
key: recordKeyFor(providerId),
|
|
2269
|
+
label: provider.name,
|
|
2270
|
+
methods: [first, ...rest],
|
|
2271
|
+
async run(session) {
|
|
2272
|
+
const models = createModels(auth);
|
|
2273
|
+
models.setProvider(provider);
|
|
2274
|
+
const type = session.method === "oauth" ? "oauth" : "api_key";
|
|
2275
|
+
await models.login(providerId, type, {
|
|
2276
|
+
signal: session.signal,
|
|
2277
|
+
notify: (event) => {
|
|
2278
|
+
relay(event, session);
|
|
2279
|
+
},
|
|
2280
|
+
prompt: (prompt) => session.prompt(restate(prompt))
|
|
2281
|
+
});
|
|
2282
|
+
}
|
|
2283
|
+
});
|
|
2284
|
+
}
|
|
2285
|
+
}
|
|
2286
|
+
//#endregion
|
|
1703
2287
|
//#region lib/types/index.js
|
|
1704
2288
|
/**
|
|
1705
2289
|
* Generic pi-ai-backed LLM adapter plugin. One plugin instance owns a dict of
|
|
@@ -1773,15 +2357,10 @@ function registrationFacts(profiles) {
|
|
|
1773
2357
|
})).sort((left, right) => left.provider.localeCompare(right.provider));
|
|
1774
2358
|
}
|
|
1775
2359
|
/**
|
|
1776
|
-
* The configurable-provider directory: every installed catalog route
|
|
1777
|
-
*
|
|
1778
|
-
*
|
|
1779
|
-
*
|
|
1780
|
-
* edit it.
|
|
1781
|
-
*
|
|
1782
|
-
* The profile half is unconditional, which is what keeps a route already
|
|
1783
|
-
* stored against a withheld provider editable and deletable rather than
|
|
1784
|
-
* stranded in the settings document with nothing on the page to remove it.
|
|
2360
|
+
* The configurable-provider directory: every installed catalog route, plus
|
|
2361
|
+
* every route the current profiles declare. A hand-declared route has no
|
|
2362
|
+
* catalog entry, so without this union it would have no settings address and
|
|
2363
|
+
* configuration surfaces could neither show nor edit it.
|
|
1785
2364
|
* @param profiles - the currently resolved provider profiles.
|
|
1786
2365
|
* @returns the directory entries in catalog order, declared routes last.
|
|
1787
2366
|
*/
|
|
@@ -1797,7 +2376,7 @@ function directoryEntries(profiles) {
|
|
|
1797
2376
|
declared: !catalog.has(provider)
|
|
1798
2377
|
});
|
|
1799
2378
|
};
|
|
1800
|
-
for (const provider of catalog)
|
|
2379
|
+
for (const provider of catalog) declare(provider, provider);
|
|
1801
2380
|
for (const [provider, profile] of profiles) declare(provider, profile.displayName);
|
|
1802
2381
|
return [...entries.values()];
|
|
1803
2382
|
}
|
|
@@ -1834,14 +2413,22 @@ function apply(ctx, config) {
|
|
|
1834
2413
|
if (hit !== void 0 && hit.length > 0) return assertUsableApiKey(hit, "llm-pi-ai", ref);
|
|
1835
2414
|
throw new LlmError(`llm-pi-ai: no credential for provider route "${provider}"; its profile resolves ${ref}, which is not set — store ${ref} through the credentials service (the web Models page writes it) or export it, and remove apiKeyEnv only if this provider should authenticate from pi-ai's own environment discovery`, "MISSING_CREDENTIAL");
|
|
1836
2415
|
};
|
|
2416
|
+
const auth = {
|
|
2417
|
+
credentials: credentialStoreFrom(ctx),
|
|
2418
|
+
authContext: authContextFrom(ctx)
|
|
2419
|
+
};
|
|
1837
2420
|
const adapter = new PiAiAdapter({
|
|
1838
2421
|
profiles,
|
|
1839
2422
|
resolveApiKey,
|
|
2423
|
+
auth,
|
|
1840
2424
|
resolveAttachments: () => ctx.get("attachments"),
|
|
1841
2425
|
onReplayDegrade: ({ provider, model, reason }) => {
|
|
1842
2426
|
ctx.logger.warn(`llm-pi-ai: unusable replay state on assistant history for route "${provider}/${model}"; sending that message as provider-neutral content (${reason})`);
|
|
1843
2427
|
}
|
|
1844
2428
|
});
|
|
2429
|
+
ctx.inject(["authorization"], (authorized) => {
|
|
2430
|
+
registerPiAiFlows(authorized, auth);
|
|
2431
|
+
});
|
|
1845
2432
|
let directory;
|
|
1846
2433
|
let directoryFacts;
|
|
1847
2434
|
const ensureDirectory = () => {
|
|
@@ -1904,4 +2491,4 @@ function apply(ctx, config) {
|
|
|
1904
2491
|
});
|
|
1905
2492
|
}
|
|
1906
2493
|
//#endregion
|
|
1907
|
-
export { Config, PiAiAdapter, apply, inject, name, supportedProtocols };
|
|
2494
|
+
export { Config, PiAiAdapter, apply, inject, name, recordKeyFor, supportedProtocols };
|