codeply-cli 0.5.1 → 0.5.2
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/LICENSE +21 -0
- package/THIRD_PARTY_NOTICES.md +65 -63
- package/bin/codeply.js +1 -1
- package/lib/agent.mjs +133 -24
- package/lib/ai.js +268 -9
- package/lib/ai.mjs +6 -6
- package/lib/apply-patch.js +217 -217
- package/lib/arity-table.json +138 -138
- package/lib/arity.js +70 -70
- package/lib/auth.mjs +6 -6
- package/lib/bots.js +82 -17
- package/lib/chatgpt.js +282 -0
- package/lib/cloud-browser.mjs +143 -143
- package/lib/cloud.mjs +1186 -1144
- package/lib/commands.js +103 -103
- package/lib/config.js +83 -3
- package/lib/design-library/assemble-artifact.mjs +21 -21
- package/lib/design-library/cleanup.mjs +45 -45
- package/lib/design-library/index.json +22379 -22379
- package/lib/design-library/make-table-data.mjs +39 -39
- package/lib/diagnostics.js +192 -192
- package/lib/edit-engine.js +364 -364
- package/lib/github-agent.mjs +311 -311
- package/lib/history.js +75 -75
- package/lib/mail-watch.js +504 -0
- package/lib/mcp.js +258 -258
- package/lib/model-sync.js +114 -0
- package/lib/native-tools.mjs +16 -1
- package/lib/oauth-connectors.js +146 -24
- package/lib/permissions.js +109 -109
- package/lib/plugins.js +353 -353
- package/lib/publish.js +916 -0
- package/lib/reach.js +67 -0
- package/lib/server.mjs +457 -457
- package/lib/session-db.js +220 -220
- package/lib/share.js +168 -168
- package/lib/skills.js +2 -0
- package/lib/snapshot.js +146 -146
- package/lib/telemetry.js +102 -0
- package/lib/terminal-hints.js +154 -154
- package/lib/tools.mjs +316 -14
- package/lib/typecheck-worker.js +147 -147
- package/lib/web-tools.js +209 -158
- package/package.json +49 -49
- package/skills/SOURCE.md +58 -58
- package/skills/accessibility/SKILL.md +147 -147
- package/skills/agent-architecture-audit/SKILL.md +257 -257
- package/skills/agent-eval/SKILL.md +147 -147
- package/skills/agent-harness-construction/SKILL.md +74 -74
- package/skills/agent-introspection-debugging/SKILL.md +154 -154
- package/skills/agent-payment-x402/SKILL.md +225 -225
- package/skills/agent-self-evaluation/SKILL.md +182 -182
- package/skills/agent-self-evaluation/references/evaluation-criteria.md +71 -71
- package/skills/agent-self-evaluation/references/hook-integration.md +64 -64
- package/skills/agent-sort/SKILL.md +216 -216
- package/skills/agentic-engineering/SKILL.md +64 -64
- package/skills/agentic-os/SKILL.md +388 -388
- package/skills/ai-first-engineering/SKILL.md +52 -52
- package/skills/ai-regression-testing/SKILL.md +386 -386
- package/skills/android-clean-architecture/SKILL.md +340 -340
- package/skills/angular-developer/SKILL.md +155 -155
- package/skills/angular-developer/references/angular-animations.md +160 -160
- package/skills/angular-developer/references/angular-aria.md +410 -410
- package/skills/angular-developer/references/cli.md +86 -86
- package/skills/angular-developer/references/component-harnesses.md +59 -59
- package/skills/angular-developer/references/component-styling.md +91 -91
- package/skills/angular-developer/references/components.md +117 -117
- package/skills/angular-developer/references/creating-services.md +97 -97
- package/skills/angular-developer/references/data-resolvers.md +69 -69
- package/skills/angular-developer/references/define-routes.md +67 -67
- package/skills/angular-developer/references/defining-providers.md +72 -72
- package/skills/angular-developer/references/di-fundamentals.md +120 -120
- package/skills/angular-developer/references/e2e-testing.md +56 -56
- package/skills/angular-developer/references/effects.md +83 -83
- package/skills/angular-developer/references/hierarchical-injectors.md +43 -43
- package/skills/angular-developer/references/host-elements.md +80 -80
- package/skills/angular-developer/references/injection-context.md +63 -63
- package/skills/angular-developer/references/inputs.md +101 -101
- package/skills/angular-developer/references/linked-signal.md +59 -59
- package/skills/angular-developer/references/loading-strategies.md +61 -61
- package/skills/angular-developer/references/mcp.md +108 -108
- package/skills/angular-developer/references/navigate-to-routes.md +69 -69
- package/skills/angular-developer/references/outputs.md +86 -86
- package/skills/angular-developer/references/reactive-forms.md +122 -122
- package/skills/angular-developer/references/rendering-strategies.md +44 -44
- package/skills/angular-developer/references/resource.md +77 -77
- package/skills/angular-developer/references/route-animations.md +56 -56
- package/skills/angular-developer/references/route-guards.md +52 -52
- package/skills/angular-developer/references/router-lifecycle.md +45 -45
- package/skills/angular-developer/references/router-testing.md +87 -87
- package/skills/angular-developer/references/show-routes-with-outlets.md +68 -68
- package/skills/angular-developer/references/signal-forms.md +795 -795
- package/skills/angular-developer/references/signals-overview.md +94 -94
- package/skills/angular-developer/references/tailwind-css.md +69 -69
- package/skills/angular-developer/references/template-driven-forms.md +114 -114
- package/skills/angular-developer/references/testing-fundamentals.md +65 -65
- package/skills/api-connector-builder/SKILL.md +121 -121
- package/skills/api-design/SKILL.md +524 -524
- package/skills/architecture-decision-records/SKILL.md +180 -180
- package/skills/article-writing/SKILL.md +80 -80
- package/skills/automation-audit-ops/SKILL.md +143 -143
- package/skills/autonomous-agent-harness/SKILL.md +274 -274
- package/skills/autonomous-loops/SKILL.md +611 -611
- package/skills/backend-patterns/SKILL.md +562 -562
- package/skills/benchmark/SKILL.md +95 -95
- package/skills/benchmark-methodology/SKILL.md +191 -191
- package/skills/benchmark-optimization-loop/SKILL.md +71 -71
- package/skills/blender-motion-state-inspection/SKILL.md +165 -165
- package/skills/blueprint/SKILL.md +106 -106
- package/skills/brand-discovery/SKILL.md +145 -145
- package/skills/brand-discovery/references/10_purpose-why.md +40 -40
- package/skills/brand-discovery/references/20_positioning.md +44 -44
- package/skills/brand-discovery/references/30_audience-niche.md +52 -52
- package/skills/brand-discovery/references/40_personality-archetype.md +57 -57
- package/skills/brand-discovery/references/50_voice-tone.md +59 -59
- package/skills/brand-discovery/references/60_narrative-story.md +50 -50
- package/skills/brand-discovery/references/70_founder-tension.md +49 -49
- package/skills/brand-discovery/references/90_SYNTHESIS.md +133 -133
- package/skills/brand-voice/SKILL.md +98 -98
- package/skills/brand-voice/references/voice-profile-schema.md +55 -55
- package/skills/browser-qa/SKILL.md +105 -105
- package/skills/bun-runtime/SKILL.md +85 -85
- package/skills/canary-watch/SKILL.md +108 -108
- package/skills/carrier-relationship-management/SKILL.md +212 -212
- package/skills/cisco-ios-patterns/SKILL.md +164 -164
- package/skills/ck/SKILL.md +148 -148
- package/skills/claude-devfleet/SKILL.md +112 -112
- package/skills/click-path-audit/SKILL.md +245 -245
- package/skills/clickhouse-io/SKILL.md +445 -445
- package/skills/code-tour/SKILL.md +254 -254
- package/skills/codebase-onboarding/SKILL.md +234 -234
- package/skills/codehealth-mcp/SKILL.md +167 -167
- package/skills/coding-standards/SKILL.md +551 -551
- package/skills/competitive-platform-analysis/SKILL.md +214 -214
- package/skills/competitive-report-structure/SKILL.md +162 -162
- package/skills/compose-multiplatform-patterns/SKILL.md +300 -300
- package/skills/config-gc/SKILL.md +120 -120
- package/skills/configure-ecc/SKILL.md +385 -385
- package/skills/connections-optimizer/SKILL.md +190 -190
- package/skills/content-engine/SKILL.md +132 -132
- package/skills/content-hash-cache-pattern/SKILL.md +162 -162
- package/skills/context-budget/SKILL.md +136 -136
- package/skills/continuous-agent-loop/SKILL.md +46 -46
- package/skills/continuous-learning/SKILL.md +132 -132
- package/skills/continuous-learning-v2/SKILL.md +361 -361
- package/skills/contract-first/SKILL.md +287 -287
- package/skills/cost-aware-llm-pipeline/SKILL.md +184 -184
- package/skills/cost-tracking/SKILL.md +97 -97
- package/skills/council/SKILL.md +204 -204
- package/skills/cpp-coding-standards/SKILL.md +724 -724
- package/skills/cpp-testing/SKILL.md +325 -325
- package/skills/crosspost/SKILL.md +112 -112
- package/skills/csharp-testing/SKILL.md +322 -322
- package/skills/customer-billing-ops/SKILL.md +141 -141
- package/skills/customs-trade-compliance/SKILL.md +263 -263
- package/skills/dart-flutter-patterns/SKILL.md +564 -564
- package/skills/dashboard-builder/SKILL.md +109 -109
- package/skills/data-scraper-agent/SKILL.md +765 -765
- package/skills/data-throughput-accelerator/SKILL.md +74 -74
- package/skills/database-migrations/SKILL.md +430 -430
- package/skills/deep-research/SKILL.md +160 -160
- package/skills/defi-amm-security/SKILL.md +167 -167
- package/skills/delivery-gate/SKILL.md +126 -126
- package/skills/deployment-patterns/SKILL.md +428 -428
- package/skills/design-system/SKILL.md +83 -83
- package/skills/django-celery/SKILL.md +458 -458
- package/skills/django-patterns/SKILL.md +735 -735
- package/skills/django-security/SKILL.md +644 -644
- package/skills/django-tdd/SKILL.md +730 -730
- package/skills/django-verification/SKILL.md +470 -470
- package/skills/dmux-workflows/SKILL.md +192 -192
- package/skills/docker-patterns/SKILL.md +365 -365
- package/skills/documentation-lookup/SKILL.md +91 -91
- package/skills/dotnet-patterns/SKILL.md +322 -322
- package/skills/dynamic-workflow-mode/SKILL.md +124 -124
- package/skills/e2e-testing/SKILL.md +327 -327
- package/skills/ecc-guide/SKILL.md +190 -190
- package/skills/ecc-recipes/SKILL.md +149 -149
- package/skills/ecc-tools-cost-audit/SKILL.md +161 -161
- package/skills/email-ops/SKILL.md +122 -122
- package/skills/energy-procurement/SKILL.md +228 -228
- package/skills/enterprise-agent-ops/SKILL.md +51 -51
- package/skills/error-handling/SKILL.md +377 -377
- package/skills/eval-harness/SKILL.md +271 -271
- package/skills/evm-token-decimals/SKILL.md +131 -131
- package/skills/exa-search/SKILL.md +108 -108
- package/skills/fal-ai-media/SKILL.md +289 -289
- package/skills/fastapi-patterns/SKILL.md +514 -514
- package/skills/finance-billing-ops/SKILL.md +128 -128
- package/skills/flox-environments/SKILL.md +497 -497
- package/skills/flutter-dart-code-review/SKILL.md +436 -436
- package/skills/foundation-models-on-device/SKILL.md +243 -243
- package/skills/frontend-a11y/SKILL.md +446 -446
- package/skills/frontend-design-direction/SKILL.md +93 -93
- package/skills/frontend-patterns/SKILL.md +657 -657
- package/skills/frontend-slides/SKILL.md +185 -185
- package/skills/fsharp-testing/SKILL.md +281 -281
- package/skills/gan-style-harness/SKILL.md +279 -279
- package/skills/gateguard/SKILL.md +133 -133
- package/skills/generating-python-installer/SKILL.md +820 -820
- package/skills/git-workflow/SKILL.md +716 -716
- package/skills/github-ops/SKILL.md +145 -145
- package/skills/golang-patterns/SKILL.md +676 -676
- package/skills/golang-testing/SKILL.md +721 -721
- package/skills/google-workspace-ops/SKILL.md +96 -96
- package/skills/growth-log/SKILL.md +128 -128
- package/skills/healthcare-cdss-patterns/SKILL.md +246 -246
- package/skills/healthcare-emr-patterns/SKILL.md +160 -160
- package/skills/healthcare-eval-harness/SKILL.md +208 -208
- package/skills/healthcare-phi-compliance/SKILL.md +146 -146
- package/skills/hermes-imports/SKILL.md +89 -89
- package/skills/hexagonal-architecture/SKILL.md +277 -277
- package/skills/hipaa-compliance/SKILL.md +79 -79
- package/skills/homelab-network-readiness/SKILL.md +170 -170
- package/skills/homelab-network-setup/SKILL.md +130 -130
- package/skills/homelab-pihole-dns/SKILL.md +275 -275
- package/skills/homelab-vlan-segmentation/SKILL.md +312 -312
- package/skills/homelab-wireguard-vpn/SKILL.md +306 -306
- package/skills/hookify-rules/SKILL.md +128 -128
- package/skills/inherit-legacy-style/SKILL.md +157 -157
- package/skills/intent-driven-development/SKILL.md +360 -360
- package/skills/inventory-demand-planning/SKILL.md +247 -247
- package/skills/investor-materials/SKILL.md +97 -97
- package/skills/investor-outreach/SKILL.md +92 -92
- package/skills/ios-icon-gen/SKILL.md +158 -158
- package/skills/iterative-retrieval/SKILL.md +212 -212
- package/skills/ito-basket-compare/SKILL.md +64 -64
- package/skills/ito-compute/SKILL.md +129 -129
- package/skills/ito-data-atlas-agent/SKILL.md +64 -64
- package/skills/ito-market-intelligence/SKILL.md +61 -61
- package/skills/ito-trade-planner/SKILL.md +68 -68
- package/skills/java-coding-standards/SKILL.md +384 -384
- package/skills/jira-integration/SKILL.md +303 -303
- package/skills/jpa-patterns/SKILL.md +152 -152
- package/skills/knowledge-ops/SKILL.md +155 -155
- package/skills/kotlin-coroutines-flows/SKILL.md +285 -285
- package/skills/kotlin-exposed-patterns/SKILL.md +720 -720
- package/skills/kotlin-ktor-patterns/SKILL.md +690 -690
- package/skills/kotlin-patterns/SKILL.md +712 -712
- package/skills/kotlin-testing/SKILL.md +825 -825
- package/skills/kubernetes-patterns/SKILL.md +756 -756
- package/skills/laravel-patterns/SKILL.md +416 -416
- package/skills/laravel-plugin-discovery/SKILL.md +230 -230
- package/skills/laravel-security/SKILL.md +948 -948
- package/skills/laravel-tdd/SKILL.md +675 -675
- package/skills/laravel-verification/SKILL.md +180 -180
- package/skills/latency-critical-systems/SKILL.md +75 -75
- package/skills/lead-intelligence/SKILL.md +322 -322
- package/skills/liquid-glass-design/SKILL.md +279 -279
- package/skills/llm-trading-agent-security/SKILL.md +147 -147
- package/skills/logistics-exception-management/SKILL.md +222 -222
- package/skills/loop-design-check/SKILL.md +143 -143
- package/skills/mailtrap-email-integration/SKILL.md +77 -77
- package/skills/make-interfaces-feel-better/SKILL.md +152 -152
- package/skills/manim-video/SKILL.md +90 -90
- package/skills/market-research/SKILL.md +76 -76
- package/skills/marketing-campaign/SKILL.md +114 -114
- package/skills/mcp-server-patterns/SKILL.md +70 -70
- package/skills/messages-ops/SKILL.md +105 -105
- package/skills/ml-adoption-playbook/SKILL.md +57 -57
- package/skills/mle-workflow/SKILL.md +348 -348
- package/skills/motion-advanced/SKILL.md +596 -596
- package/skills/motion-foundations/SKILL.md +299 -299
- package/skills/motion-patterns/SKILL.md +434 -434
- package/skills/motion-ui/SKILL.md +576 -576
- package/skills/mysql-patterns/SKILL.md +413 -413
- package/skills/nanoclaw-repl/SKILL.md +34 -34
- package/skills/nestjs-patterns/SKILL.md +231 -231
- package/skills/netmiko-ssh-automation/SKILL.md +174 -174
- package/skills/network-bgp-diagnostics/SKILL.md +168 -168
- package/skills/network-config-validation/SKILL.md +211 -211
- package/skills/network-interface-health/SKILL.md +153 -153
- package/skills/nextjs-turbopack/SKILL.md +58 -58
- package/skills/nodejs-keccak256/SKILL.md +103 -103
- package/skills/nutrient-document-processing/SKILL.md +168 -168
- package/skills/nuxt4-patterns/SKILL.md +101 -101
- package/skills/openclaw-persona-forge/SKILL.md +289 -289
- package/skills/openclaw-persona-forge/references/avatar-style.md +124 -124
- package/skills/openclaw-persona-forge/references/boundary-rules.md +53 -53
- package/skills/openclaw-persona-forge/references/error-handling.md +53 -53
- package/skills/openclaw-persona-forge/references/identity-tension.md +48 -48
- package/skills/openclaw-persona-forge/references/naming-system.md +39 -39
- package/skills/openclaw-persona-forge/references/output-template.md +166 -166
- package/skills/opensource-pipeline/SKILL.md +256 -256
- package/skills/orch-add-feature/SKILL.md +45 -45
- package/skills/orch-build-mvp/SKILL.md +49 -49
- package/skills/orch-change-feature/SKILL.md +43 -43
- package/skills/orch-fix-defect/SKILL.md +43 -43
- package/skills/orch-pipeline/SKILL.md +121 -121
- package/skills/orch-refine-code/SKILL.md +44 -44
- package/skills/parallel-execution-optimizer/SKILL.md +74 -74
- package/skills/perl-patterns/SKILL.md +505 -505
- package/skills/perl-security/SKILL.md +504 -504
- package/skills/perl-testing/SKILL.md +476 -476
- package/skills/plan-canvas/SKILL.md +153 -153
- package/skills/plan-orchestrate/SKILL.md +263 -263
- package/skills/plankton-code-quality/SKILL.md +237 -237
- package/skills/postgres-patterns/SKILL.md +148 -148
- package/skills/prediction-market-oracle-research/SKILL.md +64 -64
- package/skills/prediction-market-risk-review/SKILL.md +61 -61
- package/skills/premium-web-design/SKILL.md +154 -154
- package/skills/prisma-patterns/SKILL.md +401 -401
- package/skills/product-capability/SKILL.md +142 -142
- package/skills/product-lens/SKILL.md +93 -93
- package/skills/production-audit/SKILL.md +207 -207
- package/skills/production-scheduling/SKILL.md +238 -238
- package/skills/project-flow-ops/SKILL.md +112 -112
- package/skills/prompt-optimizer/SKILL.md +398 -398
- package/skills/publish-website/SKILL.md +76 -0
- package/skills/python-patterns/SKILL.md +751 -751
- package/skills/python-testing/SKILL.md +817 -817
- package/skills/pytorch-patterns/SKILL.md +397 -397
- package/skills/quality-nonconformance/SKILL.md +260 -260
- package/skills/quarkus-patterns/SKILL.md +723 -723
- package/skills/quarkus-security/SKILL.md +468 -468
- package/skills/quarkus-tdd/SKILL.md +812 -812
- package/skills/quarkus-verification/SKILL.md +480 -480
- package/skills/ralphinho-rfc-pipeline/SKILL.md +68 -68
- package/skills/react-native-patterns/SKILL.md +326 -326
- package/skills/react-patterns/SKILL.md +342 -342
- package/skills/react-performance/SKILL.md +575 -575
- package/skills/react-testing/SKILL.md +424 -424
- package/skills/recsys-pipeline-architect/SKILL.md +115 -115
- package/skills/recursive-decision-ledger/SKILL.md +81 -81
- package/skills/redis-patterns/SKILL.md +404 -404
- package/skills/regex-vs-llm-structured-text/SKILL.md +221 -221
- package/skills/remotion-video-creation/SKILL.md +43 -43
- package/skills/repo-scan/SKILL.md +79 -79
- package/skills/research-ops/SKILL.md +113 -113
- package/skills/returns-reverse-logistics/SKILL.md +240 -240
- package/skills/rules-distill/SKILL.md +265 -265
- package/skills/rust-patterns/SKILL.md +500 -500
- package/skills/rust-testing/SKILL.md +501 -501
- package/skills/safety-guard/SKILL.md +76 -76
- package/skills/santa-method/SKILL.md +307 -307
- package/skills/scientific-db-pubmed-database/SKILL.md +176 -176
- package/skills/scientific-db-uspto-database/SKILL.md +178 -178
- package/skills/scientific-pkg-gget/SKILL.md +167 -167
- package/skills/scientific-thinking-literature-review/SKILL.md +193 -193
- package/skills/scientific-thinking-scholar-evaluation/SKILL.md +161 -161
- package/skills/search-first/SKILL.md +183 -183
- package/skills/security-bounty-hunter/SKILL.md +100 -100
- package/skills/security-review/SKILL.md +504 -504
- package/skills/security-scan/SKILL.md +166 -166
- package/skills/seo/SKILL.md +155 -155
- package/skills/skill-comply/SKILL.md +59 -59
- package/skills/skill-scout/SKILL.md +141 -141
- package/skills/skill-stocktake/SKILL.md +195 -195
- package/skills/social-graph-ranker/SKILL.md +155 -155
- package/skills/social-publisher/SKILL.md +130 -130
- package/skills/springboot-patterns/SKILL.md +315 -315
- package/skills/springboot-security/SKILL.md +273 -273
- package/skills/springboot-tdd/SKILL.md +159 -159
- package/skills/springboot-verification/SKILL.md +232 -232
- package/skills/strategic-compact/SKILL.md +142 -142
- package/skills/swift-actor-persistence/SKILL.md +144 -144
- package/skills/swift-concurrency-6-2/SKILL.md +216 -216
- package/skills/swift-protocol-di-testing/SKILL.md +191 -191
- package/skills/swiftui-patterns/SKILL.md +259 -259
- package/skills/taste/SKILL.md +264 -264
- package/skills/taste/references/genre-taxonomy.md +87 -87
- package/skills/tdd-workflow/SKILL.md +583 -583
- package/skills/team-agent-orchestration/SKILL.md +111 -111
- package/skills/team-builder/SKILL.md +169 -169
- package/skills/terminal-ops/SKILL.md +110 -110
- package/skills/tinystruct-patterns/SKILL.md +279 -279
- package/skills/tinystruct-patterns/references/architecture.md +90 -90
- package/skills/tinystruct-patterns/references/data-handling.md +60 -60
- package/skills/tinystruct-patterns/references/database.md +99 -99
- package/skills/tinystruct-patterns/references/routing.md +64 -64
- package/skills/tinystruct-patterns/references/system-usage.md +97 -97
- package/skills/tinystruct-patterns/references/testing.md +72 -72
- package/skills/token-budget-advisor/SKILL.md +134 -134
- package/skills/ui-demo/SKILL.md +466 -466
- package/skills/ui-to-vue/SKILL.md +135 -135
- package/skills/uncloud/SKILL.md +344 -344
- package/skills/unified-memory/SKILL.md +170 -170
- package/skills/unified-notifications-ops/SKILL.md +188 -188
- package/skills/verification-loop/SKILL.md +129 -129
- package/skills/video-editing/SKILL.md +311 -311
- package/skills/videodb/SKILL.md +375 -375
- package/skills/visa-doc-translate/SKILL.md +117 -117
- package/skills/vite-patterns/SKILL.md +450 -450
- package/skills/vue-patterns/SKILL.md +471 -471
- package/skills/windows-desktop-e2e/SKILL.md +888 -888
- package/skills/workspace-surface-audit/SKILL.md +126 -126
- package/skills/x-api/SKILL.md +235 -235
package/lib/ai.js
CHANGED
|
@@ -133,6 +133,26 @@ async function withRetries(send, signal) {
|
|
|
133
133
|
// native-shaped history can never reach an endpoint that would reject it.
|
|
134
134
|
|
|
135
135
|
/** Native history -> plain text turns (tool calls described, results as user text). */
|
|
136
|
+
// reasoning_content rides along on assistant turns (agent.mjs). DeepSeek's
|
|
137
|
+
// thinking mode requires it back on every step of a tool run; everyone else
|
|
138
|
+
// gets it stripped, since some providers reject unknown message fields.
|
|
139
|
+
function wantsReasoningBack(url, model) {
|
|
140
|
+
return /deepseek/i.test(String(url || '')) || /deepseek/i.test(String(model || ''));
|
|
141
|
+
}
|
|
142
|
+
function wireMessages(messages, url, model) {
|
|
143
|
+
if (wantsReasoningBack(url, model)) {
|
|
144
|
+
// A step with no reasoning still needs the field (an empty one is accepted).
|
|
145
|
+
if (!messages.some((m) => m && m.role === 'assistant' && m.tool_calls && m.reasoning_content === undefined)) return messages;
|
|
146
|
+
return messages.map((m) => (m && m.role === 'assistant' && m.tool_calls && m.reasoning_content === undefined ? { ...m, reasoning_content: '' } : m));
|
|
147
|
+
}
|
|
148
|
+
if (!messages.some((m) => m && m.reasoning_content !== undefined)) return messages;
|
|
149
|
+
return messages.map((m) => {
|
|
150
|
+
if (!m || m.reasoning_content === undefined) return m;
|
|
151
|
+
const { reasoning_content, ...rest } = m;
|
|
152
|
+
return rest;
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
136
156
|
function textOnlyMessages(messages) {
|
|
137
157
|
if (!messages.some((m) => m.role === 'tool' || m.tool_calls)) return messages;
|
|
138
158
|
const out = [];
|
|
@@ -141,7 +161,7 @@ function textOnlyMessages(messages) {
|
|
|
141
161
|
out.push({ role: 'user', content: `[tool result: ${m.name || 'tool'}]\n${typeof m.content === 'string' ? m.content : JSON.stringify(m.content)}` });
|
|
142
162
|
} else if (m.tool_calls) {
|
|
143
163
|
const calls = m.tool_calls.map((c) => `[called ${c.function?.name}(${String(c.function?.arguments || '').slice(0, 400)})]`).join('\n');
|
|
144
|
-
out.push({ role: 'assistant', content: [m.content || '', calls].filter(Boolean).join('\n') });
|
|
164
|
+
out.push({ role: 'assistant', content: [m.content || '', calls].filter(Boolean).join('\n'), ...(m.reasoning_content !== undefined ? { reasoning_content: m.reasoning_content } : {}) });
|
|
145
165
|
} else {
|
|
146
166
|
out.push(m);
|
|
147
167
|
}
|
|
@@ -274,7 +294,7 @@ async function chatViaProxy(messages, opts) {
|
|
|
274
294
|
// the proxy logs it to usage_history so CLI activity shows up in the
|
|
275
295
|
// admin dashboard next to the desktop app, same as this app's own calls.
|
|
276
296
|
// The proxy declares no tools, so it only ever gets text history.
|
|
277
|
-
body: JSON.stringify({ messages: textOnlyMessages(messages), opts: { ...opts, tools: undefined }, meta: opts.meta }),
|
|
297
|
+
body: JSON.stringify({ messages: wireMessages(textOnlyMessages(messages)), opts: { ...opts, tools: undefined }, meta: opts.meta }),
|
|
278
298
|
signal,
|
|
279
299
|
});
|
|
280
300
|
body = await res.json().catch(() => ({}));
|
|
@@ -376,6 +396,22 @@ async function chatViaOllama(messages, opts, cfg) {
|
|
|
376
396
|
return last;
|
|
377
397
|
}
|
|
378
398
|
|
|
399
|
+
// Newer models refuse a temperature setting ("temperature is deprecated for
|
|
400
|
+
// this model": Claude 4.5 and later, OpenAI's o-series and GPT-5). Those never
|
|
401
|
+
// get one; any other model that refuses it once is remembered and retried
|
|
402
|
+
// straight away without it.
|
|
403
|
+
const NO_TEMPERATURE = /^(claude-(opus|sonnet|haiku)-(4-[5-9]|[5-9])|claude-fable|o\d|gpt-5)/i;
|
|
404
|
+
const temperatureRefused = new Set();
|
|
405
|
+
const sendsTemperature = (model) => !NO_TEMPERATURE.test(String(model || '').replace(/^[\w.-]+\//, '')) && !temperatureRefused.has(model);
|
|
406
|
+
const temperatureParam = (model, opts) => (sendsTemperature(model) ? { temperature: opts.temperature ?? 0 } : {});
|
|
407
|
+
/** The provider refused the temperature: remember it for this model, and say whether to retry. */
|
|
408
|
+
function refusedTemperature(model, msg) {
|
|
409
|
+
if (!/temperature/i.test(msg) || !/deprecat|not supported|unsupported|does not support|only the default|not allowed|invalid/i.test(msg)) return false;
|
|
410
|
+
if (temperatureRefused.has(model)) return false;
|
|
411
|
+
temperatureRefused.add(model);
|
|
412
|
+
return true;
|
|
413
|
+
}
|
|
414
|
+
|
|
379
415
|
function ollamaRequest(host, model, apiKey, isLocal, messages, opts, numCtx, hasSpare) {
|
|
380
416
|
return streamingChatRequest({
|
|
381
417
|
url: `${host}/v1/chat/completions`, label: 'Ollama', model, apiKey, isLocal, messages, opts, hasSpare,
|
|
@@ -410,8 +446,8 @@ async function streamingChatRequest({ url, label, model, apiKey, isLocal, messag
|
|
|
410
446
|
headers,
|
|
411
447
|
body: JSON.stringify({
|
|
412
448
|
model,
|
|
413
|
-
messages: opts.tools ? messages : textOnlyMessages(messages),
|
|
414
|
-
|
|
449
|
+
messages: wireMessages(opts.tools ? messages : textOnlyMessages(messages), url, model),
|
|
450
|
+
...temperatureParam(model, opts),
|
|
415
451
|
...(opts.maxTokens ? { max_tokens: opts.maxTokens } : {}),
|
|
416
452
|
...(opts.json ? { response_format: { type: 'json_object' } } : {}),
|
|
417
453
|
...(opts.tools ? { tools: opts.tools, tool_choice: 'auto' } : {}),
|
|
@@ -449,6 +485,7 @@ async function streamingChatRequest({ url, label, model, apiKey, isLocal, messag
|
|
|
449
485
|
const apiError = body?.error?.message || body?.error;
|
|
450
486
|
if (apiError) {
|
|
451
487
|
const msg = typeof apiError === 'string' ? apiError : JSON.stringify(apiError);
|
|
488
|
+
if (refusedTemperature(model, msg)) return { retryable: true, retryAfterMs: 0, error: `${label}: ${msg}` };
|
|
452
489
|
const fatal = /not found|does not exist|unknown model|unauthor|invalid.*key|forbidden/i.test(msg);
|
|
453
490
|
if (fatal) return { done: true, value: { success: false, error: `${label}: ${msg}` } };
|
|
454
491
|
// Another account is standing by, and this failure is this account's
|
|
@@ -616,8 +653,8 @@ async function chatViaOpenAICompatible(messages, opts, providerName, cfg) {
|
|
|
616
653
|
},
|
|
617
654
|
body: JSON.stringify({
|
|
618
655
|
model,
|
|
619
|
-
messages: opts.tools ? messages : textOnlyMessages(messages),
|
|
620
|
-
|
|
656
|
+
messages: wireMessages(opts.tools ? messages : textOnlyMessages(messages), url, model),
|
|
657
|
+
...temperatureParam(model, opts),
|
|
621
658
|
...(opts.maxTokens ? { max_tokens: opts.maxTokens } : {}),
|
|
622
659
|
...(opts.json ? { response_format: { type: 'json_object' } } : {}),
|
|
623
660
|
...(opts.tools ? { tools: opts.tools, tool_choice: 'auto' } : {}),
|
|
@@ -645,6 +682,7 @@ async function chatViaOpenAICompatible(messages, opts, providerName, cfg) {
|
|
|
645
682
|
const apiError = body?.error?.message || body?.error;
|
|
646
683
|
if (apiError) {
|
|
647
684
|
const msg = typeof apiError === 'string' ? apiError : JSON.stringify(apiError);
|
|
685
|
+
if (refusedTemperature(model, msg)) return { retryable: true, retryAfterMs: 0, error: `${label}: ${msg}` };
|
|
648
686
|
const fatal = /not found|does not exist|unknown model|unauthor|invalid.*key|forbidden/i.test(msg);
|
|
649
687
|
if (fatal) return { done: true, value: { success: false, error: `${label}: ${msg}` } };
|
|
650
688
|
return { retryable: isTransientStatus(res.status), retryAfterMs: retryAfterMs(res), error: `${label}: ${msg}` };
|
|
@@ -768,7 +806,7 @@ async function chatViaAnthropic(messages, opts, cfg) {
|
|
|
768
806
|
system,
|
|
769
807
|
messages: turns,
|
|
770
808
|
max_tokens: opts.maxTokens || 8192,
|
|
771
|
-
|
|
809
|
+
...temperatureParam(model, opts),
|
|
772
810
|
...(opts.tools ? { tools: toAnthropicTools(opts.tools) } : {}),
|
|
773
811
|
}),
|
|
774
812
|
signal: opts.signal,
|
|
@@ -916,11 +954,13 @@ async function chatViaOllamaNative(messages, opts, m) {
|
|
|
916
954
|
cleanup();
|
|
917
955
|
if (isTimeout()) return { retryable: true, error: `Ollama at ${host} didn't respond in time. Large models can take a while to load - try again, or pick a smaller model.` };
|
|
918
956
|
if (isAbortError(e)) return { aborted: true };
|
|
957
|
+
if (m.research === 'local') return { done: true, value: { success: false, error: researchMode().ERR_LOCAL_DOWN } };
|
|
919
958
|
return { retryable: false, error: local ? `Can't reach Ollama at ${host}. Is Ollama running? (Start it with \`ollama serve\` or open the Ollama app.)` : `Can't reach ${host}: ${e.message}` };
|
|
920
959
|
}
|
|
921
960
|
|
|
922
961
|
if (!res.ok) {
|
|
923
962
|
cleanup();
|
|
963
|
+
if (m.research === 'cloud' && (res.status === 401 || res.status === 403)) return { done: true, value: { success: false, error: researchMode().ERR_CLOUD_KEY } };
|
|
924
964
|
const body = await res.json().catch(() => ({}));
|
|
925
965
|
const msg = body.error || describeStatus(res.status);
|
|
926
966
|
const fatal = res.status === 404 || /not found|pull/i.test(String(msg));
|
|
@@ -945,7 +985,10 @@ async function chatViaOllamaNative(messages, opts, m) {
|
|
|
945
985
|
let evt;
|
|
946
986
|
try { evt = JSON.parse(line); } catch { continue; }
|
|
947
987
|
if (evt.error) streamError = evt.error;
|
|
948
|
-
if (evt.message?.content)
|
|
988
|
+
if (evt.message?.content) {
|
|
989
|
+
content += evt.message.content;
|
|
990
|
+
if (opts.onToken) { try { opts.onToken(evt.message.content); } catch {} }
|
|
991
|
+
}
|
|
949
992
|
if (evt.message?.thinking) reasoning += evt.message.thinking;
|
|
950
993
|
// Ollama sends each tool call whole (arguments as an object).
|
|
951
994
|
for (const tc of evt.message?.tool_calls || []) {
|
|
@@ -974,7 +1017,176 @@ async function chatViaOllamaNative(messages, opts, m) {
|
|
|
974
1017
|
}, opts.signal);
|
|
975
1018
|
}
|
|
976
1019
|
|
|
1020
|
+
// ─── ChatGPT plan (Sign in with ChatGPT) ────────────────────────────────────
|
|
1021
|
+
// The token from chatgpt.js only works against the Responses API, and only
|
|
1022
|
+
// with store:false + stream:true. Craft's history is chat-completions shaped,
|
|
1023
|
+
// so it's converted on the way in and the stream reassembled into the same
|
|
1024
|
+
// {choices:[{message}]} shape every other path returns.
|
|
1025
|
+
|
|
1026
|
+
function toResponsesContent(content, role) {
|
|
1027
|
+
if (typeof content === 'string' || !Array.isArray(content)) {
|
|
1028
|
+
return [{ type: role === 'assistant' ? 'output_text' : 'input_text', text: String(content || '') }];
|
|
1029
|
+
}
|
|
1030
|
+
return content.map((p) => {
|
|
1031
|
+
if (p.type === 'image_url') return { type: 'input_image', image_url: p.image_url?.url || p.image_url };
|
|
1032
|
+
return { type: role === 'assistant' ? 'output_text' : 'input_text', text: p.text || '' };
|
|
1033
|
+
});
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
function toResponsesRequest(messages, opts) {
|
|
1037
|
+
const instructions = [];
|
|
1038
|
+
const input = [];
|
|
1039
|
+
for (const m of opts.tools ? messages : textOnlyMessages(messages)) {
|
|
1040
|
+
if (m.role === 'system') {
|
|
1041
|
+
instructions.push(typeof m.content === 'string' ? m.content : toResponsesContent(m.content).map((p) => p.text).join('\n'));
|
|
1042
|
+
} else if (m.role === 'tool') {
|
|
1043
|
+
input.push({ type: 'function_call_output', call_id: m.tool_call_id, output: typeof m.content === 'string' ? m.content : JSON.stringify(m.content) });
|
|
1044
|
+
} else {
|
|
1045
|
+
const hasText = Array.isArray(m.content) ? m.content.length > 0 : !!m.content;
|
|
1046
|
+
if (hasText) input.push({ role: m.role, content: toResponsesContent(m.content, m.role) });
|
|
1047
|
+
for (const c of m.tool_calls || []) {
|
|
1048
|
+
input.push({ type: 'function_call', call_id: c.id, name: c.function?.name, arguments: c.function?.arguments || '{}' });
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
const body = { model: opts.model, input, store: false, stream: true };
|
|
1053
|
+
if (instructions.length) body.instructions = instructions.join('\n\n');
|
|
1054
|
+
if (opts.maxTokens) body.max_output_tokens = Math.max(16, opts.maxTokens);
|
|
1055
|
+
if (opts.tools) {
|
|
1056
|
+
body.tools = opts.tools.map((t) => ({ type: 'function', name: t.function.name, description: t.function.description, parameters: t.function.parameters }));
|
|
1057
|
+
body.tool_choice = 'auto';
|
|
1058
|
+
}
|
|
1059
|
+
return body;
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
// Plan-usage errors come back as structured codes; these are the ones a
|
|
1063
|
+
// person can act on (developers.openai.com/siwc/token-sharing-open-source/errors-and-recovery).
|
|
1064
|
+
function chatgptErrorMessage(code, fallback) {
|
|
1065
|
+
switch (code) {
|
|
1066
|
+
case 'subscription_sharing_usage_limit_exceeded':
|
|
1067
|
+
return 'You reached the ChatGPT plan usage allowed for Craft. Manage usage at chatgpt.com/settings/usage, or pick another model.';
|
|
1068
|
+
case 'subscription_sharing_user_not_eligible':
|
|
1069
|
+
return 'Your ChatGPT plan or workspace can’t be used in other apps. Pick another model, or check your plan at chatgpt.com.';
|
|
1070
|
+
case 'subscription_sharing_invalid_user':
|
|
1071
|
+
return 'Your ChatGPT sign-in is no longer valid. Sign in again from the model menu.';
|
|
1072
|
+
case 'subscription_sharing_unsupported_capability':
|
|
1073
|
+
return `ChatGPT plan models don’t support part of this request (${fallback}).`;
|
|
1074
|
+
default:
|
|
1075
|
+
return fallback;
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
const CHATGPT_RETRYABLE = new Set(['subscription_sharing_usage_unavailable', 'subscription_sharing_user_unavailable']);
|
|
1079
|
+
|
|
1080
|
+
async function chatViaChatGPT(messages, opts, m) {
|
|
1081
|
+
const chatgpt = require('./chatgpt.js');
|
|
1082
|
+
const label = m.name || m.model;
|
|
1083
|
+
let refreshed = false;
|
|
1084
|
+
return withRetries(async () => {
|
|
1085
|
+
let token;
|
|
1086
|
+
try { token = await chatgpt.accessToken({ force: refreshed }); } catch (e) {
|
|
1087
|
+
return { done: true, value: { success: false, error: e.message } };
|
|
1088
|
+
}
|
|
1089
|
+
let res;
|
|
1090
|
+
const { signal, poke, isTimeout, cleanup } = withIdleTimeout(opts.signal, REQUEST_TIMEOUT_MS);
|
|
1091
|
+
try {
|
|
1092
|
+
res = await fetch(`${chatgpt.RESOURCE}/responses`, {
|
|
1093
|
+
method: 'POST',
|
|
1094
|
+
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
|
|
1095
|
+
body: JSON.stringify(toResponsesRequest(messages, { ...opts, model: m.model })),
|
|
1096
|
+
signal,
|
|
1097
|
+
});
|
|
1098
|
+
} catch (e) {
|
|
1099
|
+
cleanup();
|
|
1100
|
+
if (isTimeout()) return { retryable: true, error: `${label} timed out with no response - retrying.` };
|
|
1101
|
+
if (isAbortError(e)) return { aborted: true };
|
|
1102
|
+
return { retryable: true, error: `Couldn't reach ChatGPT: ${e.message}` };
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
if (!res.ok) {
|
|
1106
|
+
cleanup();
|
|
1107
|
+
const body = await res.json().catch(() => ({}));
|
|
1108
|
+
const code = body?.error?.code || body?.code;
|
|
1109
|
+
const msg = body?.error?.message || describeStatus(res.status);
|
|
1110
|
+
// An expired access token: refresh once and go again.
|
|
1111
|
+
if (res.status === 401 && !refreshed && code !== 'subscription_sharing_invalid_user') {
|
|
1112
|
+
refreshed = true;
|
|
1113
|
+
return { retryable: true, retryAfterMs: 0, error: msg };
|
|
1114
|
+
}
|
|
1115
|
+
const text = `${label}: ${chatgptErrorMessage(code, msg)}`;
|
|
1116
|
+
if (CHATGPT_RETRYABLE.has(code) || res.status === 503) return { retryable: true, retryAfterMs: retryAfterMs(res), error: text };
|
|
1117
|
+
return { done: true, value: { success: false, error: text } };
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
let content = '';
|
|
1121
|
+
let reasoning = '';
|
|
1122
|
+
let modelUsed = m.model;
|
|
1123
|
+
let failure = null;
|
|
1124
|
+
let completed = false;
|
|
1125
|
+
const toolCalls = [];
|
|
1126
|
+
let buffer = '';
|
|
1127
|
+
try {
|
|
1128
|
+
for await (const chunk of res.body) {
|
|
1129
|
+
poke();
|
|
1130
|
+
buffer += Buffer.isBuffer(chunk) ? chunk.toString('utf8') : Buffer.from(chunk).toString('utf8');
|
|
1131
|
+
let nl;
|
|
1132
|
+
while ((nl = buffer.indexOf('\n')) !== -1) {
|
|
1133
|
+
const line = buffer.slice(0, nl).trim();
|
|
1134
|
+
buffer = buffer.slice(nl + 1);
|
|
1135
|
+
if (!line.startsWith('data:')) continue;
|
|
1136
|
+
const payload = line.slice(5).trim();
|
|
1137
|
+
if (!payload || payload === '[DONE]') continue;
|
|
1138
|
+
let evt;
|
|
1139
|
+
try { evt = JSON.parse(payload); } catch { continue; }
|
|
1140
|
+
switch (evt.type) {
|
|
1141
|
+
case 'response.output_text.delta': content += evt.delta || ''; break;
|
|
1142
|
+
case 'response.reasoning_summary_text.delta':
|
|
1143
|
+
case 'response.reasoning_text.delta': reasoning += evt.delta || ''; break;
|
|
1144
|
+
case 'response.output_item.done':
|
|
1145
|
+
if (evt.item?.type === 'function_call') {
|
|
1146
|
+
toolCalls.push({
|
|
1147
|
+
id: evt.item.call_id || evt.item.id || `call_${Date.now().toString(36)}_${toolCalls.length}`,
|
|
1148
|
+
type: 'function',
|
|
1149
|
+
function: { name: evt.item.name, arguments: evt.item.arguments || '{}' },
|
|
1150
|
+
});
|
|
1151
|
+
}
|
|
1152
|
+
break;
|
|
1153
|
+
case 'response.completed':
|
|
1154
|
+
completed = true;
|
|
1155
|
+
modelUsed = evt.response?.model || modelUsed;
|
|
1156
|
+
break;
|
|
1157
|
+
case 'response.failed':
|
|
1158
|
+
case 'response.incomplete':
|
|
1159
|
+
case 'error': {
|
|
1160
|
+
const err = evt.response?.error || evt.error || evt;
|
|
1161
|
+
failure = { code: err.code, message: err.message || evt.response?.incomplete_details?.reason || 'the response did not finish' };
|
|
1162
|
+
break;
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
} catch (e) {
|
|
1168
|
+
if (isTimeout()) return { retryable: true, error: `${label} stopped sending data mid-response (stalled stream) - retrying.` };
|
|
1169
|
+
if (isAbortError(e)) return { aborted: true };
|
|
1170
|
+
return { retryable: true, error: `${label} stream interrupted: ${e.message}` };
|
|
1171
|
+
} finally {
|
|
1172
|
+
cleanup();
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
if (failure && !content && !toolCalls.length) {
|
|
1176
|
+
const text = `${label}: ${chatgptErrorMessage(failure.code, failure.message)}`;
|
|
1177
|
+
return CHATGPT_RETRYABLE.has(failure.code) ? { retryable: true, error: text } : { done: true, value: { success: false, error: text } };
|
|
1178
|
+
}
|
|
1179
|
+
if (!completed && !content && !toolCalls.length) return { retryable: true, error: `${label} ended the stream without an answer - retrying.` };
|
|
1180
|
+
|
|
1181
|
+
const message = { role: 'assistant', content };
|
|
1182
|
+
if (reasoning) message.reasoning = reasoning;
|
|
1183
|
+
if (toolCalls.length) message.tool_calls = toolCalls;
|
|
1184
|
+
return { done: true, value: { success: true, data: { choices: [{ message, finish_reason: toolCalls.length ? 'tool_calls' : 'stop' }], model: modelUsed }, modelUsed } };
|
|
1185
|
+
}, opts.signal);
|
|
1186
|
+
}
|
|
1187
|
+
|
|
977
1188
|
function chatViaCustom(messages, opts, m) {
|
|
1189
|
+
if (m.kind === 'chatgpt') return chatViaChatGPT(messages, opts, m);
|
|
978
1190
|
if (m.kind === 'ollama') return chatViaOllamaNative(messages, opts, m);
|
|
979
1191
|
const url = chatCompletionsUrl(m.baseUrl);
|
|
980
1192
|
const local = isLocalUrl(url);
|
|
@@ -1033,7 +1245,54 @@ async function chatViaAuto(messages, opts) {
|
|
|
1033
1245
|
return r;
|
|
1034
1246
|
}
|
|
1035
1247
|
|
|
1248
|
+
/**
|
|
1249
|
+
* Research Mode: all inference goes to local Ollama (/api/chat) or Ollama
|
|
1250
|
+
* Cloud (bearer key), streaming through chatViaOllamaNative. opts.onToken
|
|
1251
|
+
* receives each token as it arrives.
|
|
1252
|
+
*/
|
|
1253
|
+
function researchMode() {
|
|
1254
|
+
const ollama = require('../research-mode/ollama.js');
|
|
1255
|
+
const pre = require('../research-mode/preprocessor.js');
|
|
1256
|
+
return { ...ollama, ...pre };
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
async function chatResearch(messages, opts, rm) {
|
|
1260
|
+
const rmod = researchMode();
|
|
1261
|
+
const target = rmod.resolveTarget(rm);
|
|
1262
|
+
if (target.error) return { success: false, error: target.error };
|
|
1263
|
+
if (!rm.model) return { success: false, error: 'Pick a model in Research Mode settings.' };
|
|
1264
|
+
const pre = rmod.preprocess({ messages, mode: rm.mode, model: rm.model, researchContext: rm.context });
|
|
1265
|
+
return chatViaOllamaNative(rmod.withSystem(pre), opts, { baseUrl: target.host, model: rm.model, apiKey: target.apiKey, research: rm.mode === 'cloud' ? 'cloud' : 'local' });
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
/** Which route a request takes, for the usage counts (telemetry.js). */
|
|
1269
|
+
function providerOf(opts) {
|
|
1270
|
+
const rm = getConfig().research;
|
|
1271
|
+
if (rm && rm.enabled) return 'research';
|
|
1272
|
+
if (opts.route && opts.route.custom) return opts.route.custom.kind === 'chatgpt' ? 'chatgpt' : opts.route.custom.kind === 'ollama' ? 'ollama' : 'byok';
|
|
1273
|
+
if (opts.route && opts.route.auto) return 'auto';
|
|
1274
|
+
const p = applyRoute(getConfig(), opts.route).provider;
|
|
1275
|
+
return p === 'ollama' ? 'ollama' : ['anthropic', 'openrouter', 'groq', 'openai', 'google', 'qwen', 'deepseek'].includes(p) ? 'byok' : 'proxy';
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
/** Every model call, counted (which app, which model, tokens; never content). */
|
|
1036
1279
|
async function chat(messages, opts = {}) {
|
|
1280
|
+
const started = Date.now();
|
|
1281
|
+
const r = await chatRouted(messages, opts);
|
|
1282
|
+
if (r && r.success) {
|
|
1283
|
+
try {
|
|
1284
|
+
const telemetry = require('./telemetry.js');
|
|
1285
|
+
const model = r.modelUsed || (r.data && r.data.model) || (opts.route && opts.route.custom && opts.route.custom.model) || '';
|
|
1286
|
+
telemetry.recordAi({ model: String(model).slice(0, 120), provider: providerOf(opts), ms: Date.now() - started, ...telemetry.tokensOf(r.data, messages) });
|
|
1287
|
+
} catch {}
|
|
1288
|
+
}
|
|
1289
|
+
return r;
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
async function chatRouted(messages, opts = {}) {
|
|
1293
|
+
// Research Mode, when switched on in settings, takes every request.
|
|
1294
|
+
const rm = getConfig().research;
|
|
1295
|
+
if (rm && rm.enabled) return chatResearch(messages, opts, rm);
|
|
1037
1296
|
// A user-added model (desktop model picker) always wins when routed.
|
|
1038
1297
|
if (opts.route && opts.route.custom) return chatViaCustom(messages, opts, opts.route.custom);
|
|
1039
1298
|
// Auto in the desktop app = the hosted Codeply model, regardless of what
|
|
@@ -1104,4 +1363,4 @@ async function chatJson(messages, opts = {}) {
|
|
|
1104
1363
|
return { success: true, json: parsed, usage: r.data.usage || {}, modelUsed: r.modelUsed };
|
|
1105
1364
|
}
|
|
1106
1365
|
|
|
1107
|
-
module.exports = { chat, chatJson, isRateLimitError, listOllamaModels, testModel, chatCompletionsUrl };
|
|
1366
|
+
module.exports = { chatResearch, chat, chatJson, isRateLimitError, listOllamaModels, testModel, chatCompletionsUrl };
|
package/lib/ai.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { createRequire } from 'module';
|
|
2
|
-
const require = createRequire(import.meta.url);
|
|
3
|
-
|
|
4
|
-
const ai = require('../lib/ai.js');
|
|
5
|
-
export default ai;
|
|
6
|
-
export const { chat, chatJson, isRateLimitError } = ai;
|
|
1
|
+
import { createRequire } from 'module';
|
|
2
|
+
const require = createRequire(import.meta.url);
|
|
3
|
+
|
|
4
|
+
const ai = require('../lib/ai.js');
|
|
5
|
+
export default ai;
|
|
6
|
+
export const { chat, chatJson, isRateLimitError } = ai;
|