Quellcode durchsuchen

downgrade to ai sdk v4.x

Dax Raad vor 8 Monaten
Ursprung
Commit
fa1266263d
5 geänderte Dateien mit 249 neuen und 155 gelöschten Zeilen
  1. 23 5
      bun.lock
  2. 1 1
      package.json
  3. 19 10
      packages/opencode/src/bun/index.ts
  4. 1 1
      packages/opencode/src/provider/models.ts
  5. 205 138
      packages/opencode/src/session/index.ts

+ 23 - 5
bun.lock

@@ -91,16 +91,18 @@
   },
   },
   "catalog": {
   "catalog": {
     "@types/node": "22.13.9",
     "@types/node": "22.13.9",
-    "ai": "5.0.0-alpha.7",
+    "ai": "4.3.16",
     "typescript": "5.8.2",
     "typescript": "5.8.2",
     "zod": "3.24.2",
     "zod": "3.24.2",
   },
   },
   "packages": {
   "packages": {
-    "@ai-sdk/gateway": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0-alpha.7", "@ai-sdk/provider-utils": "3.0.0-alpha.7" }, "peerDependencies": { "zod": "^3.24.0" } }, "sha512-gz1V165eiJnQIexfLyKm11vimrmQ3zdcJhPpjeLFmDU9wrvZwLuklfZ0WgfYSb+EjiP1cKypwt6JSGvWkfKIAQ=="],
+    "@ai-sdk/provider": ["@ai-sdk/[email protected]", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg=="],
 
 
-    "@ai-sdk/provider": ["@ai-sdk/[email protected]", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-lhdrARU3SSmt5p/GNNK7VhazvZpKSCIOjpHUfX7f5jIhVGi/vvlxP1rD6Go57nn1MtuGKNqL04AebSRFDQsQbw=="],
+    "@ai-sdk/provider-utils": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "1.1.3", "nanoid": "^3.3.8", "secure-json-parse": "^2.7.0" }, "peerDependencies": { "zod": "^3.23.8" } }, "sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA=="],
 
 
-    "@ai-sdk/provider-utils": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "2.0.0-alpha.7", "@standard-schema/spec": "^1.0.0", "zod-to-json-schema": "^3.24.1" }, "peerDependencies": { "zod": "^3.23.8" } }, "sha512-AYkT3jskmo7Lwzijo/yHKD1jC+UZizsROO8ULTg9aJZUwR4ABZzAxh4NxDIEy4TWRfBGufp+/9ICHAn6pkU71w=="],
+    "@ai-sdk/react": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider-utils": "2.2.8", "@ai-sdk/ui-utils": "1.2.11", "swr": "^2.2.5", "throttleit": "2.1.0" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc", "zod": "^3.23.8" }, "optionalPeers": ["zod"] }, "sha512-jK1IZZ22evPZoQW3vlkZ7wvjYGYF+tRBKXtrcolduIkQ/m/sOAVcVeVDUDvh1T91xCnWCdUGCPZg2avZ90mv3g=="],
+
+    "@ai-sdk/ui-utils": ["@ai-sdk/[email protected]", "", { "dependencies": { "@ai-sdk/provider": "1.1.3", "@ai-sdk/provider-utils": "2.2.8", "zod-to-json-schema": "^3.24.1" }, "peerDependencies": { "zod": "^3.23.8" } }, "sha512-3zcwCc8ezzFlwp3ZD15wAPjf2Au4s3vAbKsXQVyhxODHcmu0iyPO2Eua6D/vicq/AUm/BAo60r97O6HU+EI0+w=="],
 
 
     "@ampproject/remapping": ["@ampproject/[email protected]", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="],
     "@ampproject/remapping": ["@ampproject/[email protected]", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="],
 
 
@@ -430,6 +432,8 @@
 
 
     "@types/debug": ["@types/[email protected]", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="],
     "@types/debug": ["@types/[email protected]", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="],
 
 
+    "@types/diff-match-patch": ["@types/[email protected]", "", {}, "sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg=="],
+
     "@types/estree": ["@types/[email protected]", "", {}, "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="],
     "@types/estree": ["@types/[email protected]", "", {}, "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="],
 
 
     "@types/estree-jsx": ["@types/[email protected]", "", { "dependencies": { "@types/estree": "*" } }, "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg=="],
     "@types/estree-jsx": ["@types/[email protected]", "", { "dependencies": { "@types/estree": "*" } }, "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg=="],
@@ -474,7 +478,7 @@
 
 
     "acorn-walk": ["[email protected]", "", {}, "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A=="],
     "acorn-walk": ["[email protected]", "", {}, "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A=="],
 
 
-    "ai": ["ai@5.0.0-alpha.7", "", { "dependencies": { "@ai-sdk/gateway": "1.0.0-alpha.7", "@ai-sdk/provider": "2.0.0-alpha.7", "@ai-sdk/provider-utils": "3.0.0-alpha.7", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.23.8" } }, "sha512-ShCk3frIMdVtK9knvWKiFS7N6Vwnf8mLMv670+T//W9oqfoetSVPBhTF6Dy+oDM/bjVSsBf1BuYImLDvHICOIQ=="],
+    "ai": ["ai@4.3.16", "", { "dependencies": { "@ai-sdk/provider": "1.1.3", "@ai-sdk/provider-utils": "2.2.8", "@ai-sdk/react": "1.2.12", "@ai-sdk/ui-utils": "1.2.11", "@opentelemetry/api": "1.9.0", "jsondiffpatch": "0.6.0" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc", "zod": "^3.23.8" }, "optionalPeers": ["react"] }, "sha512-KUDwlThJ5tr2Vw0A1ZkbDKNME3wzWhuVfAOwIvFUzl1TPVDFAXDFTXio3p+jaKneB+dKNCvFFlolYmmgHttG1g=="],
 
 
     "ansi-align": ["[email protected]", "", { "dependencies": { "string-width": "^4.1.0" } }, "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w=="],
     "ansi-align": ["[email protected]", "", { "dependencies": { "string-width": "^4.1.0" } }, "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w=="],
 
 
@@ -686,6 +690,8 @@
 
 
     "diff": ["[email protected]", "", {}, "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg=="],
     "diff": ["[email protected]", "", {}, "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg=="],
 
 
+    "diff-match-patch": ["[email protected]", "", {}, "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw=="],
+
     "direction": ["[email protected]", "", { "bin": { "direction": "cli.js" } }, "sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA=="],
     "direction": ["[email protected]", "", { "bin": { "direction": "cli.js" } }, "sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA=="],
 
 
     "dlv": ["[email protected]", "", {}, "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="],
     "dlv": ["[email protected]", "", {}, "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="],
@@ -970,6 +976,8 @@
 
 
     "json5": ["[email protected]", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
     "json5": ["[email protected]", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
 
 
+    "jsondiffpatch": ["[email protected]", "", { "dependencies": { "@types/diff-match-patch": "^1.0.36", "chalk": "^5.3.0", "diff-match-patch": "^1.0.5" }, "bin": { "jsondiffpatch": "bin/jsondiffpatch.js" } }, "sha512-3QItJOXp2AP1uv7waBkao5nCvhEv+QmJAd38Ybq7wNI74Q+BBmnLn4EDKz6yI9xGAIQoUF87qHt+kc1IVxB4zQ=="],
+
     "kleur": ["[email protected]", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="],
     "kleur": ["[email protected]", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="],
 
 
     "klona": ["[email protected]", "", {}, "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA=="],
     "klona": ["[email protected]", "", {}, "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA=="],
@@ -1274,6 +1282,8 @@
 
 
     "rc": ["[email protected]", "", { "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "bin": { "rc": "./cli.js" } }, "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw=="],
     "rc": ["[email protected]", "", { "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "bin": { "rc": "./cli.js" } }, "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw=="],
 
 
+    "react": ["[email protected]", "", {}, "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg=="],
+
     "readable-stream": ["[email protected]", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="],
     "readable-stream": ["[email protected]", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="],
 
 
     "readdirp": ["[email protected]", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
     "readdirp": ["[email protected]", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
@@ -1354,6 +1364,8 @@
 
 
     "sax": ["[email protected]", "", {}, "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA=="],
     "sax": ["[email protected]", "", {}, "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA=="],
 
 
+    "secure-json-parse": ["[email protected]", "", {}, "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw=="],
+
     "semver": ["[email protected]", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
     "semver": ["[email protected]", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
 
 
     "send": ["[email protected]", "", { "dependencies": { "debug": "^4.3.5", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.0", "mime-types": "^3.0.1", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.1" } }, "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw=="],
     "send": ["[email protected]", "", { "dependencies": { "debug": "^4.3.5", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.0", "mime-types": "^3.0.1", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.1" } }, "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw=="],
@@ -1454,6 +1466,8 @@
 
 
     "supports-color": ["[email protected]", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
     "supports-color": ["[email protected]", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
 
 
+    "swr": ["[email protected]", "", { "dependencies": { "dequal": "^2.0.3", "use-sync-external-store": "^1.4.0" }, "peerDependencies": { "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-dshNvs3ExOqtZ6kJBaAsabhPdHyeY4P2cKwRCniDVifBMoG/SVI7tfLWqPXriVspf2Rg4tPzXJTnwaihIeFw2A=="],
+
     "tar-fs": ["[email protected]", "", { "dependencies": { "pump": "^3.0.0", "tar-stream": "^3.1.5" }, "optionalDependencies": { "bare-fs": "^4.0.1", "bare-path": "^3.0.0" } }, "sha512-XF4w9Xp+ZQgifKakjZYmFdkLoSWd34VGKcsTCwlNWM7QG3ZbaxnTsaBwnjFZqHRf/rROxaR8rXnbtwdvaDI+lA=="],
     "tar-fs": ["[email protected]", "", { "dependencies": { "pump": "^3.0.0", "tar-stream": "^3.1.5" }, "optionalDependencies": { "bare-fs": "^4.0.1", "bare-path": "^3.0.0" } }, "sha512-XF4w9Xp+ZQgifKakjZYmFdkLoSWd34VGKcsTCwlNWM7QG3ZbaxnTsaBwnjFZqHRf/rROxaR8rXnbtwdvaDI+lA=="],
 
 
     "tar-stream": ["[email protected]", "", { "dependencies": { "b4a": "^1.6.4", "fast-fifo": "^1.2.0", "streamx": "^2.15.0" } }, "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ=="],
     "tar-stream": ["[email protected]", "", { "dependencies": { "b4a": "^1.6.4", "fast-fifo": "^1.2.0", "streamx": "^2.15.0" } }, "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ=="],
@@ -1462,6 +1476,8 @@
 
 
     "thread-stream": ["[email protected]", "", { "dependencies": { "real-require": "^0.1.0" } }, "sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA=="],
     "thread-stream": ["[email protected]", "", { "dependencies": { "real-require": "^0.1.0" } }, "sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA=="],
 
 
+    "throttleit": ["[email protected]", "", {}, "sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw=="],
+
     "tiny-inflate": ["[email protected]", "", {}, "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw=="],
     "tiny-inflate": ["[email protected]", "", {}, "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw=="],
 
 
     "tinyexec": ["[email protected]", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="],
     "tinyexec": ["[email protected]", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="],
@@ -1546,6 +1562,8 @@
 
 
     "url": ["[email protected]", "", { "dependencies": { "punycode": "1.3.2", "querystring": "0.2.0" } }, "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ=="],
     "url": ["[email protected]", "", { "dependencies": { "punycode": "1.3.2", "querystring": "0.2.0" } }, "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ=="],
 
 
+    "use-sync-external-store": ["[email protected]", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A=="],
+
     "util": ["[email protected]", "", { "dependencies": { "inherits": "^2.0.3", "is-arguments": "^1.0.4", "is-generator-function": "^1.0.7", "is-typed-array": "^1.1.3", "which-typed-array": "^1.1.2" } }, "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA=="],
     "util": ["[email protected]", "", { "dependencies": { "inherits": "^2.0.3", "is-arguments": "^1.0.4", "is-generator-function": "^1.0.7", "is-typed-array": "^1.1.3", "which-typed-array": "^1.1.2" } }, "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA=="],
 
 
     "util-deprecate": ["[email protected]", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
     "util-deprecate": ["[email protected]", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],

+ 1 - 1
package.json

@@ -15,7 +15,7 @@
       "typescript": "5.8.2",
       "typescript": "5.8.2",
       "@types/node": "22.13.9",
       "@types/node": "22.13.9",
       "zod": "3.24.2",
       "zod": "3.24.2",
-      "ai": "5.0.0-alpha.7"
+      "ai": "4.3.16"
     }
     }
   },
   },
   "devDependencies": {
   "devDependencies": {

+ 19 - 10
packages/opencode/src/bun/index.ts

@@ -44,15 +44,24 @@ export namespace BunProc {
     }),
     }),
   )
   )
   export async function install(pkg: string, version = "latest") {
   export async function install(pkg: string, version = "latest") {
-    const dir = path.join(Global.Path.cache, `node_modules`, pkg)
-    if (!(await Bun.file(path.join(dir, "package.json")).exists())) {
-      log.info("installing", { pkg })
-      await BunProc.run(["add", `${pkg}@${version}`], {
-        cwd: Global.Path.cache,
-      }).catch(() => {
-        throw new InstallFailedError({ pkg, version })
-      })
-    }
-    return dir
+    const mod = path.join(Global.Path.cache, "node_modules", pkg)
+    const pkgjson = Bun.file(path.join(Global.Path.cache, "package.json"))
+    const parsed = await pkgjson.json().catch(() => ({
+      dependencies: {},
+    }))
+    if (parsed.dependencies[pkg] === version) return mod
+    parsed.dependencies[pkg] = version
+    await Bun.write(pkgjson, JSON.stringify(parsed, null, 2))
+    await BunProc.run(["install"], {
+      cwd: Global.Path.cache,
+    }).catch((e) => {
+      new InstallFailedError(
+        { pkg, version },
+        {
+          cause: e,
+        },
+      )
+    })
+    return mod
   }
   }
 }
 }

+ 1 - 1
packages/opencode/src/provider/models.ts

@@ -86,7 +86,7 @@ export namespace ModelsDev {
   export async function pkg(providerID: string): Promise<[string, string]> {
   export async function pkg(providerID: string): Promise<[string, string]> {
     const packages = await aisdk()
     const packages = await aisdk()
     const match = packages[`@ai-sdk/${providerID}`]
     const match = packages[`@ai-sdk/${providerID}`]
-    if (match) return [match.package.name, "alpha"]
+    if (match) return [match.package.name, "latest"]
     return [providerID, "latest"]
     return [providerID, "latest"]
   }
   }
 }
 }

+ 205 - 138
packages/opencode/src/session/index.ts

@@ -4,15 +4,15 @@ import { Identifier } from "../id/id"
 import { Storage } from "../storage/storage"
 import { Storage } from "../storage/storage"
 import { Log } from "../util/log"
 import { Log } from "../util/log"
 import {
 import {
-  convertToModelMessages,
   generateText,
   generateText,
   LoadAPIKeyError,
   LoadAPIKeyError,
-  stepCountIs,
   streamText,
   streamText,
   tool,
   tool,
   type Tool as AITool,
   type Tool as AITool,
   type LanguageModelUsage,
   type LanguageModelUsage,
-  type UIMessage,
+  type CoreMessage,
+  type UserContent,
+  type AssistantContent,
 } from "ai"
 } from "ai"
 import { z, ZodSchema } from "zod"
 import { z, ZodSchema } from "zod"
 import { Decimal } from "decimal.js"
 import { Decimal } from "decimal.js"
@@ -28,6 +28,7 @@ import { NamedError } from "../util/error"
 import type { Tool } from "../tool/tool"
 import type { Tool } from "../tool/tool"
 import { SystemPrompt } from "./system"
 import { SystemPrompt } from "./system"
 import { Flag } from "../flag/flag"
 import { Flag } from "../flag/flag"
+import type { ModelsDev } from "../provider/models"
 
 
 export namespace Session {
 export namespace Session {
   const log = Log.create({ service: "session" })
   const log = Log.create({ service: "session" })
@@ -227,34 +228,28 @@ export namespace Session {
     const session = await get(input.sessionID)
     const session = await get(input.sessionID)
     if (msgs.length === 0 && !session.parentID) {
     if (msgs.length === 0 && !session.parentID) {
       generateText({
       generateText({
-        maxOutputTokens: 20,
-        messages: convertToModelMessages([
+        maxTokens: input.providerID === "google" ? 1024 : 20,
+        messages: [
           ...SystemPrompt.title(input.providerID).map(
           ...SystemPrompt.title(input.providerID).map(
-            (x): UIMessage => ({
-              id: Identifier.ascending("message"),
+            (x): CoreMessage => ({
               role: "system",
               role: "system",
-              parts: [
-                {
-                  type: "text",
-                  text: x,
-                },
-              ],
+              content: x,
             }),
             }),
           ),
           ),
           {
           {
             role: "user",
             role: "user",
-            parts: input.parts,
+            content: toUserContent(input.parts),
           },
           },
-        ]),
-        temperature: 0,
+        ],
         model: model.language,
         model: model.language,
       })
       })
         .then((result) => {
         .then((result) => {
-          return Session.update(input.sessionID, (draft) => {
-            draft.title = result.text
-          })
+          if (result.text)
+            return Session.update(input.sessionID, (draft) => {
+              draft.title = result.text
+            })
         })
         })
-        .catch(() => {})
+        .catch((e) => {})
     }
     }
     const msg: Message.Info = {
     const msg: Message.Info = {
       role: "user",
       role: "user",
@@ -400,90 +395,9 @@ export namespace Session {
         }
         }
         text = undefined
         text = undefined
       },
       },
-      async onChunk(input) {
-        const value = input.chunk
-        l.info("part", {
-          type: value.type,
-        })
-        switch (value.type) {
-          case "text":
-            if (!text) {
-              text = value
-              next.parts.push(value)
-              break
-            } else text.text += value.text
-            break
-
-          case "tool-call": {
-            const [match] = next.parts.flatMap((p) =>
-              p.type === "tool-invocation" &&
-              p.toolInvocation.toolCallId === value.toolCallId
-                ? [p]
-                : [],
-            )
-            if (!match) break
-            match.toolInvocation.args = value.args
-            match.toolInvocation.state = "call"
-            Bus.publish(Message.Event.PartUpdated, {
-              part: match,
-              messageID: next.id,
-              sessionID: next.metadata.sessionID,
-            })
-            break
-          }
-
-          case "tool-call-streaming-start":
-            next.parts.push({
-              type: "tool-invocation",
-              toolInvocation: {
-                state: "partial-call",
-                toolName: value.toolName,
-                toolCallId: value.toolCallId,
-                args: {},
-              },
-            })
-            Bus.publish(Message.Event.PartUpdated, {
-              part: next.parts[next.parts.length - 1],
-              messageID: next.id,
-              sessionID: next.metadata.sessionID,
-            })
-            break
-
-          case "tool-call-delta":
-            break
-
-          case "tool-result":
-            const match = next.parts.find(
-              (p) =>
-                p.type === "tool-invocation" &&
-                p.toolInvocation.toolCallId === value.toolCallId,
-            )
-            if (match && match.type === "tool-invocation") {
-              match.toolInvocation = {
-                args: value.args,
-                toolCallId: value.toolCallId,
-                toolName: value.toolName,
-                state: "result",
-                result: value.result as string,
-              }
-              Bus.publish(Message.Event.PartUpdated, {
-                part: match,
-                messageID: next.id,
-                sessionID: next.metadata.sessionID,
-              })
-            }
-            break
-
-          default:
-            l.info("unhandled", {
-              type: value.type,
-            })
-        }
-        await updateMessage(next)
-      },
       async onFinish(input) {
       async onFinish(input) {
         const assistant = next.metadata!.assistant!
         const assistant = next.metadata!.assistant!
-        const usage = getUsage(input.totalUsage, model.info)
+        const usage = getUsage(input.usage, model.info)
         assistant.cost = usage.cost
         assistant.cost = usage.cost
         await updateMessage(next)
         await updateMessage(next)
       },
       },
@@ -515,31 +429,44 @@ export namespace Session {
           error: next.metadata.error,
           error: next.metadata.error,
         })
         })
       },
       },
-      async prepareStep(step) {
-        next.parts.push({
-          type: "step-start",
-        })
-        await updateMessage(next)
-        return step
-      },
+      // async prepareStep(step) {
+      //   next.parts.push({
+      //     type: "step-start",
+      //   })
+      //   await updateMessage(next)
+      //   return step
+      // },
       toolCallStreaming: true,
       toolCallStreaming: true,
       abortSignal: abort.signal,
       abortSignal: abort.signal,
-      stopWhen: stepCountIs(1000),
-      messages: convertToModelMessages([
+      maxSteps: 1000,
+      messages: [
         ...system.map(
         ...system.map(
-          (x): UIMessage => ({
-            id: Identifier.ascending("message"),
+          (x): CoreMessage => ({
             role: "system",
             role: "system",
-            parts: [
-              {
-                type: "text",
-                text: x,
-              },
-            ],
+            content: x,
           }),
           }),
         ),
         ),
-        ...msgs,
-      ]),
+        ...msgs.flatMap((msg): CoreMessage[] => {
+          switch (msg.role) {
+            case "user":
+              return [
+                {
+                  role: "user",
+                  content: toUserContent(msg.parts),
+                },
+              ]
+            case "assistant":
+              return [
+                {
+                  role: "assistant",
+                  content: toAssistantContent(msg.parts),
+                },
+              ]
+            default:
+              return []
+          }
+        }),
+      ],
       temperature: model.info.id === "codex-mini-latest" ? undefined : 0,
       temperature: model.info.id === "codex-mini-latest" ? undefined : 0,
       tools: {
       tools: {
         ...(await MCP.tools()),
         ...(await MCP.tools()),
@@ -547,6 +474,101 @@ export namespace Session {
       },
       },
       model: model.language,
       model: model.language,
     })
     })
+    for await (const value of result.fullStream) {
+      l.info("part", {
+        type: value.type,
+      })
+      switch (value.type) {
+        case "step-start":
+          next.parts.push({
+            type: "step-start",
+          })
+          break
+        case "text-delta":
+          if (!text) {
+            text = {
+              type: "text",
+              text: value.textDelta,
+            }
+            next.parts.push(text)
+            break
+          } else text.text += value.textDelta
+          break
+
+        case "tool-call": {
+          const [match] = next.parts.flatMap((p) =>
+            p.type === "tool-invocation" &&
+            p.toolInvocation.toolCallId === value.toolCallId
+              ? [p]
+              : [],
+          )
+          if (!match) break
+          match.toolInvocation.args = value.args
+          match.toolInvocation.state = "call"
+          Bus.publish(Message.Event.PartUpdated, {
+            part: match,
+            messageID: next.id,
+            sessionID: next.metadata.sessionID,
+          })
+          break
+        }
+
+        case "tool-call-streaming-start":
+          next.parts.push({
+            type: "tool-invocation",
+            toolInvocation: {
+              state: "partial-call",
+              toolName: value.toolName,
+              toolCallId: value.toolCallId,
+              args: {},
+            },
+          })
+          Bus.publish(Message.Event.PartUpdated, {
+            part: next.parts[next.parts.length - 1],
+            messageID: next.id,
+            sessionID: next.metadata.sessionID,
+          })
+          break
+
+        case "tool-call-delta":
+          break
+
+        // for some reason ai sdk claims to not send this part but it does
+        // @ts-expect-error
+        case "tool-result":
+          const match = next.parts.find(
+            (p) =>
+              p.type === "tool-invocation" &&
+              // @ts-expect-error
+              p.toolInvocation.toolCallId === value.toolCallId,
+          )
+          if (match && match.type === "tool-invocation") {
+            match.toolInvocation = {
+              // @ts-expect-error
+              args: value.args,
+              // @ts-expect-error
+              toolCallId: value.toolCallId,
+              // @ts-expect-error
+              toolName: value.toolName,
+              state: "result",
+              // @ts-expect-error
+              result: value.result as string,
+            }
+            Bus.publish(Message.Event.PartUpdated, {
+              part: match,
+              messageID: next.id,
+              sessionID: next.metadata.sessionID,
+            })
+          }
+          break
+
+        default:
+          l.info("unhandled", {
+            type: value.type,
+          })
+      }
+      await updateMessage(next)
+    }
     await result.consumeStream({
     await result.consumeStream({
       onError: (err) => {
       onError: (err) => {
         log.error("stream error", {
         log.error("stream error", {
@@ -618,30 +640,23 @@ export namespace Session {
     const result = await generateText({
     const result = await generateText({
       abortSignal: abort.signal,
       abortSignal: abort.signal,
       model: model.language,
       model: model.language,
-      messages: convertToModelMessages([
+      messages: [
         ...system.map(
         ...system.map(
-          (x): UIMessage => ({
-            id: Identifier.ascending("message"),
+          (x): CoreMessage => ({
             role: "system",
             role: "system",
-            parts: [
-              {
-                type: "text",
-                text: x,
-              },
-            ],
+            content: x,
           }),
           }),
         ),
         ),
-        ...filtered,
         {
         {
           role: "user",
           role: "user",
-          parts: [
+          content: toUserContent([
             {
             {
               type: "text",
               type: "text",
               text: "Provide a detailed but concise summary of our conversation above. Focus on information that would be helpful for continuing the conversation, including what we did, what we're doing, which files we're working on, and what we're going to do next.",
               text: "Provide a detailed but concise summary of our conversation above. Focus on information that would be helpful for continuing the conversation, including what we did, what we're doing, which files we're working on, and what we're going to do next.",
             },
             },
-          ],
+          ]),
         },
         },
-      ]),
+      ],
     })
     })
     next.parts.push({
     next.parts.push({
       type: "text",
       type: "text",
@@ -669,11 +684,11 @@ export namespace Session {
     }
     }
   }
   }
 
 
-  function getUsage(usage: LanguageModelUsage, model: Provider.Model) {
+  function getUsage(usage: LanguageModelUsage, model: ModelsDev.Model) {
     const tokens = {
     const tokens = {
-      input: usage.inputTokens ?? 0,
-      output: usage.outputTokens ?? 0,
-      reasoning: usage.reasoningTokens ?? 0,
+      input: usage.promptTokens ?? 0,
+      output: usage.completionTokens ?? 0,
+      reasoning: 0,
     }
     }
     return {
     return {
       cost: new Decimal(0)
       cost: new Decimal(0)
@@ -710,3 +725,55 @@ export namespace Session {
     await App.initialize()
     await App.initialize()
   }
   }
 }
 }
+
+function toAssistantContent(parts: Message.Part[]): AssistantContent {
+  const result: AssistantContent = []
+  for (const part of parts) {
+    switch (part.type) {
+      case "text":
+        result.push({ type: "text", text: part.text })
+        break
+      case "file":
+        result.push({
+          type: "file",
+          data: new URL(part.url),
+          mimeType: part.mediaType,
+          filename: part.filename,
+        })
+        break
+      case "tool-invocation":
+        result.push({
+          type: "tool-call",
+          args: part.toolInvocation.args,
+          toolName: part.toolInvocation.toolName,
+          toolCallId: part.toolInvocation.toolCallId,
+        })
+        break
+      default:
+        break
+    }
+  }
+  return result
+}
+
+function toUserContent(parts: Message.Part[]): UserContent {
+  const result: UserContent = []
+  for (const part of parts) {
+    switch (part.type) {
+      case "text":
+        return [{ type: "text", text: part.text }]
+      case "file":
+        return [
+          {
+            type: "file",
+            filename: part.filename,
+            data: new URL(part.url),
+            mimeType: part.mediaType,
+          },
+        ]
+      default:
+        return []
+    }
+  }
+  return result
+}