@heyputer/puter.js 2.1.15 → 2.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heyputer/puter.js",
3
- "version": "2.1.15",
3
+ "version": "2.2.2",
4
4
  "description": "Puter.js - A JavaScript library for interacting with Puter services.",
5
5
  "homepage": "https://developer.puter.com",
6
6
  "main": "src/index.js",
@@ -42,7 +42,6 @@
42
42
  "webpack-cli": "^5.1.4"
43
43
  },
44
44
  "dependencies": {
45
- "@heyputer/kv.js": "^0.2.1",
46
- "@heyputer/putility": "^1.1.1"
45
+ "@heyputer/kv.js": "^0.2.1"
47
46
  }
48
47
  }
package/src/index.js CHANGED
@@ -1,5 +1,3 @@
1
- import putility from '@heyputer/putility';
2
-
3
1
  import kvjs from '@heyputer/kv.js';
4
2
  import APICallLogger from './lib/APICallLogger.js';
5
3
  import path from './lib/path.js';
@@ -24,12 +22,69 @@ import Threads from './modules/Threads.js';
24
22
  import UI from './modules/UI.js';
25
23
  import Util from './modules/Util.js';
26
24
  import { WorkersHandler } from './modules/Workers.js';
27
- import { APIAccessService } from './services/APIAccess.js';
28
- import { FilesystemService } from './services/Filesystem.js';
29
- import { FSRelayService } from './services/FSRelay.js';
30
- import { NoPuterYetService } from './services/NoPuterYet.js';
31
- import { XDIncomingService } from './services/XDIncoming.js';
32
25
 
26
+ class SimpleLogger {
27
+ constructor (fields = {}) {
28
+ this.fieldsObj = fields;
29
+ this.enabled = new Set();
30
+ }
31
+
32
+ on (category) {
33
+ this.enabled.add(category);
34
+ }
35
+
36
+ fields (extra = {}) {
37
+ return new SimpleLogger({ ...this.fieldsObj, ...extra });
38
+ }
39
+
40
+ info (...args) {
41
+ console.log(...this._prefix(), ...args);
42
+ }
43
+
44
+ warn (...args) {
45
+ console.warn(...this._prefix(), ...args);
46
+ }
47
+
48
+ error (...args) {
49
+ console.error(...this._prefix(), ...args);
50
+ }
51
+
52
+ debug (...args) {
53
+ console.debug(...this._prefix(), ...args);
54
+ }
55
+
56
+ _prefix () {
57
+ const entries = Object.entries(this.fieldsObj);
58
+ if ( !entries.length ) return [];
59
+ return [`[${ entries.map(([k, v]) => `${k}=${v}`).join(' ')}]`];
60
+ }
61
+ }
62
+
63
+ class Lock {
64
+ constructor () {
65
+ this.locked = false;
66
+ this.queue = [];
67
+ }
68
+
69
+ async acquire () {
70
+ if ( !this.locked ) {
71
+ this.locked = true;
72
+ return;
73
+ }
74
+
75
+ await new Promise(resolve => this.queue.push(resolve));
76
+ this.locked = true;
77
+ }
78
+
79
+ release () {
80
+ const next = this.queue.shift();
81
+ if ( next ) {
82
+ next();
83
+ return;
84
+ }
85
+ this.locked = false;
86
+ }
87
+ }
33
88
  // TODO: This is for a safe-guard below; we should check if we can
34
89
  // generalize this behavior rather than hard-coding it.
35
90
  // (using defaultGUIOrigin breaks locally-hosted apps)
@@ -135,15 +190,6 @@ const puterInit = (function () {
135
190
 
136
191
  // "modules" in puter.js are external interfaces for the developer
137
192
  this.modules_ = [];
138
- // "services" in puter.js are used by modules and may interact with each other
139
- const context = new putility.libs.context.Context()
140
- .follow(this, ['env', 'util', 'authToken', 'APIOrigin', 'appID']);
141
-
142
- context.puter = this;
143
-
144
- this.services = new putility.system.ServiceManager({ context });
145
- this.context = context;
146
- context.services = this.services;
147
193
 
148
194
  // Holds the query parameters found in the current URL
149
195
  let URLParams = new URLSearchParams(globalThis.location?.search);
@@ -261,57 +307,15 @@ const puterInit = (function () {
261
307
 
262
308
  // === START :: Logger ===
263
309
 
264
- // logger will log to console
265
- let logger = new putility.libs.log.ConsoleLogger();
266
-
267
- // logs can be toggled based on categories
268
- logger = new putility.libs.log.CategorizedToggleLogger({ delegate: logger });
269
- const cat_logger = logger;
270
-
271
- // create facade for easy logging
272
- this.logger = new putility.libs.log.LoggerFacade({
273
- impl: logger,
274
- cat: cat_logger,
275
- });
310
+ // Basic logger replacement (console-based)
311
+ let logger = new SimpleLogger();
312
+ this.logger = logger;
276
313
 
277
314
  // Initialize API call logger
278
315
  this.apiCallLogger = new APICallLogger({
279
316
  enabled: false, // Disabled by default
280
317
  });
281
318
 
282
- // === START :: Services === //
283
-
284
- this.services.register('no-puter-yet', NoPuterYetService);
285
- this.services.register('filesystem', FilesystemService);
286
- this.services.register('api-access', APIAccessService);
287
- this.services.register('xd-incoming', XDIncomingService);
288
- if ( this.env !== 'app' ) {
289
- this.services.register('fs-relay', FSRelayService);
290
- }
291
-
292
- // When api-access is initialized, bind `.authToken` and
293
- // `.APIOrigin` as a 1-1 mapping with the `puter` global
294
- (async () => {
295
- await this.services.wait_for_init(['api-access']);
296
- const svc_apiAccess = this.services.get('api-access');
297
-
298
- svc_apiAccess.auth_token = this.authToken;
299
- svc_apiAccess.api_origin = this.APIOrigin;
300
- [
301
- ['authToken', 'auth_token'],
302
- ['APIOrigin', 'api_origin'],
303
- ].forEach(([k1, k2]) => {
304
- Object.defineProperty(this, k1, {
305
- get () {
306
- return svc_apiAccess[k2];
307
- },
308
- set (v) {
309
- svc_apiAccess[k2] = v;
310
- },
311
- });
312
- });
313
- })();
314
-
315
319
  // === Start :: Modules === //
316
320
 
317
321
  // The SDK is running in the Puter GUI (i.e. 'gui')
@@ -365,31 +369,27 @@ const puterInit = (function () {
365
369
 
366
370
  // Add prefix logger (needed to happen after modules are initialized)
367
371
  (async () => {
368
- await this.services.wait_for_init(['api-access']);
369
- const whoami = await this.auth.whoami();
370
- logger = new putility.libs.log.PrefixLogger({
371
- delegate: logger,
372
- prefix: `[${
372
+ try {
373
+ const whoami = await this.auth.whoami();
374
+ const prefix = `[${
373
375
  whoami?.app_name ?? this.appInstanceID ?? 'HOST'
374
- }] `,
375
- });
376
-
377
- this.logger.impl = logger;
376
+ }]`;
377
+ logger = logger.fields({ prefix });
378
+ this.logger = logger;
379
+ } catch (error) {
380
+ if ( this.debugMode ) {
381
+ console.error('Failed to initialize prefix logger', error);
382
+ }
383
+ }
378
384
  })();
379
385
 
380
386
  // Lock to prevent multiple requests to `/rao`
381
- this.lock_rao_ = new putility.libs.promise.Lock();
387
+ this.lock_rao_ = new Lock();
382
388
  // Promise that resolves when it's okay to request `/rao`
383
- this.p_can_request_rao_ = new putility.libs.promise.TeePromise();
389
+ this.p_can_request_rao_ = Promise.resolve();
384
390
  // Flag that indicates if a request to `/rao` has been made
385
391
  this.rao_requested_ = false;
386
392
 
387
- // In case we're already auth'd, request `/rao`
388
- (async () => {
389
- await this.services.wait_for_init(['api-access']);
390
- this.p_can_request_rao_.resolve();
391
- })();
392
-
393
393
  this.net = {
394
394
  generateWispV1URL: async () => {
395
395
  const { token: wispToken, server: wispServer } = (await (await fetch(`${this.APIOrigin }/wisp/relay-token/create`, {
@@ -457,7 +457,7 @@ const puterInit = (function () {
457
457
  }
458
458
 
459
459
  registerModule (name, cls, parameters = {}) {
460
- const instance = new cls(this.context, parameters);
460
+ const instance = new cls(this, parameters);
461
461
  instance.puter = this;
462
462
  this.modules_.push(name);
463
463
  this[name] = instance;
@@ -518,6 +518,25 @@ const puterInit = (function () {
518
518
  this.updateSubmodules();
519
519
  };
520
520
 
521
+ runWhenPuterHappensCallbacks = function () {
522
+ if ( this.env !== 'gui' ) return;
523
+ if ( ! globalThis.when_puter_happens ) return;
524
+
525
+ const callbacks = Array.isArray(globalThis.when_puter_happens)
526
+ ? globalThis.when_puter_happens
527
+ : [globalThis.when_puter_happens];
528
+
529
+ for ( const fn of callbacks ) {
530
+ try {
531
+ fn({ puter: this });
532
+ } catch ( error ) {
533
+ if ( this.debugMode ) {
534
+ console.error('when_puter_happens callback failed', error);
535
+ }
536
+ }
537
+ }
538
+ };
539
+
521
540
  resetAuthToken = function () {
522
541
  this.authToken = null;
523
542
  // If the SDK is running on a 3rd-party site or an app, then save the authToken in localStorage
@@ -785,6 +804,7 @@ const puterInit = (function () {
785
804
  export const puter = puterInit();
786
805
  export default puter;
787
806
  globalThis.puter = puter;
807
+ puter.runWhenPuterHappensCallbacks();
788
808
 
789
809
  puter.tools = [];
790
810
  /**
@@ -863,4 +883,4 @@ globalThis.addEventListener && globalThis.addEventListener('message', async (eve
863
883
  puter.puterAuthState.resolver = null;
864
884
  };
865
885
  }
866
- });
886
+ });
package/src/lib/utils.js CHANGED
@@ -65,6 +65,16 @@ function uuidv4 () {
65
65
  (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16));
66
66
  }
67
67
 
68
+ const createDeferred = () => {
69
+ let resolve;
70
+ let reject;
71
+ const promise = new Promise((res, rej) => {
72
+ resolve = res;
73
+ reject = rej;
74
+ });
75
+ return { promise, resolve, reject };
76
+ };
77
+
68
78
  /**
69
79
  * Initializes and returns an XMLHttpRequest object configured for a specific API endpoint, method, and headers.
70
80
  *
@@ -266,11 +276,11 @@ function make_driver_method (arg_defs, driverInterface, driverName, driverMethod
266
276
  }
267
277
 
268
278
  async function driverCall (options, driverInterface, driverName, driverMethod, driverArgs, settings) {
269
- const tp = new TeePromise();
279
+ const deferred = createDeferred();
270
280
 
271
281
  driverCall_(options,
272
- tp.resolve.bind(tp),
273
- tp.reject.bind(tp),
282
+ deferred.resolve,
283
+ deferred.reject,
274
284
  driverInterface,
275
285
  driverName,
276
286
  driverMethod,
@@ -279,7 +289,7 @@ async function driverCall (options, driverInterface, driverName, driverMethod, d
279
289
  undefined,
280
290
  settings);
281
291
 
282
- return await tp;
292
+ return await deferred.promise;
283
293
  }
284
294
 
285
295
  // This function encapsulates the logic for sending a driver call request
@@ -368,9 +378,9 @@ async function driverCall_ (
368
378
  is_stream = true;
369
379
  const Stream = async function* Stream () {
370
380
  while ( !response_complete ) {
371
- const tp = new TeePromise();
372
- signal_stream_update = tp.resolve.bind(tp);
373
- await tp;
381
+ const signal = createDeferred();
382
+ signal_stream_update = signal.resolve;
383
+ await signal.promise;
374
384
  if ( response_complete ) break;
375
385
  while ( lines_received.length > 0 ) {
376
386
  const line = lines_received.shift();
@@ -543,58 +553,16 @@ async function driverCall_ (
543
553
  args: driverArgs,
544
554
  auth_token: puter.authToken,
545
555
  }));
546
- }
547
556
 
548
- class TeePromise {
549
- static STATUS_PENDING = {};
550
- static STATUS_RUNNING = {};
551
- static STATUS_DONE = {};
552
- constructor () {
553
- this.status_ = this.constructor.STATUS_PENDING;
554
- this.donePromise = new Promise((resolve, reject) => {
555
- this.doneResolve = resolve;
556
- this.doneReject = reject;
557
- });
558
- }
559
- get status () {
560
- return this.status_;
561
- }
562
- set status (status) {
563
- this.status_ = status;
564
- if ( status === this.constructor.STATUS_DONE ) {
565
- this.doneResolve();
566
- }
567
- }
568
- resolve (value) {
569
- this.status_ = this.constructor.STATUS_DONE;
570
- this.doneResolve(value);
571
- }
572
- awaitDone () {
573
- return this.donePromise;
574
- }
575
- then (fn, rfn) {
576
- return this.donePromise.then(fn, rfn);
577
- }
578
-
579
- reject (err) {
580
- this.status_ = this.constructor.STATUS_DONE;
581
- this.doneReject(err);
582
- }
583
-
584
- /**
585
- * @deprecated use then() instead
586
- */
587
- onComplete (fn) {
588
- return this.then(fn);
589
- }
590
557
  }
591
558
 
592
559
  async function blob_to_url (blob) {
593
- const tp = new TeePromise();
594
560
  const reader = new (globalThis.FileReader || FileReaderPoly)();
595
- reader.onloadend = () => tp.resolve(reader.result);
596
- reader.readAsDataURL(blob);
597
- return await tp;
561
+ return await new Promise((resolve, reject) => {
562
+ reader.onloadend = () => resolve(reader.result);
563
+ reader.onerror = reject;
564
+ reader.readAsDataURL(blob);
565
+ });
598
566
  }
599
567
 
600
568
  function blobToDataUri (blob) {
@@ -625,5 +593,5 @@ function arrayBufferToDataUri (arrayBuffer) {
625
593
  }
626
594
 
627
595
  export {
628
- arrayBufferToDataUri, blob_to_url, blobToDataUri, driverCall, handle_error, handle_resp, initXhr, make_driver_method, parseResponse, setupXhrEventHandlers, TeePromise, uuidv4
596
+ arrayBufferToDataUri, blob_to_url, blobToDataUri, driverCall, handle_error, handle_resp, initXhr, make_driver_method, parseResponse, setupXhrEventHandlers, uuidv4
629
597
  };
package/src/modules/AI.js CHANGED
@@ -11,33 +11,6 @@ const normalizeTTSProvider = (value) => {
11
11
  return value;
12
12
  };
13
13
 
14
- const TOGETHER_IMAGE_MODEL_PREFIXES = [
15
- 'black-forest-labs/',
16
- 'stabilityai/',
17
- 'togethercomputer/',
18
- 'playgroundai/',
19
- 'runwayml/',
20
- 'lightricks/',
21
- 'sg161222/',
22
- 'wavymulder/',
23
- 'prompthero/',
24
- 'bytedance-seed/',
25
- 'hidream-ai/',
26
- 'lykon/',
27
- 'qwen/',
28
- 'rundiffusion/',
29
- 'google/',
30
- 'ideogram/',
31
- ];
32
-
33
- const TOGETHER_IMAGE_MODEL_KEYWORDS = [
34
- 'flux',
35
- 'kling',
36
- 'sd3',
37
- 'stable-diffusion',
38
- 'kolors',
39
- ];
40
-
41
14
  const TOGETHER_VIDEO_MODEL_PREFIXES = [
42
15
  'minimax/',
43
16
  'google/',
@@ -57,10 +30,11 @@ class AI {
57
30
  * @param {string} APIOrigin - Origin of the API server. Used to build the API endpoint URLs.
58
31
  * @param {string} appID - ID of the app to use.
59
32
  */
60
- constructor (context) {
61
- this.authToken = context.authToken;
62
- this.APIOrigin = context.APIOrigin;
63
- this.appID = context.appID;
33
+ constructor (puter) {
34
+ this.puter = puter;
35
+ this.authToken = puter.authToken;
36
+ this.APIOrigin = puter.APIOrigin;
37
+ this.appID = puter.appID;
64
38
  }
65
39
 
66
40
  /**
@@ -666,7 +640,7 @@ class AI {
666
640
  let testMode = false;
667
641
 
668
642
  // default driver is openai-completion
669
- let driver = 'openai-completion';
643
+ let driver = 'ai-chat';
670
644
 
671
645
  // Check that the argument is not undefined or null
672
646
  if ( ! args ) {
@@ -765,160 +739,6 @@ class AI {
765
739
  // convert undefined to empty string so that .startsWith works
766
740
  requestParams.model = requestParams.model ?? '';
767
741
 
768
- // If model starts with "anthropic/", remove it
769
- // later on we should standardize the model names to [vendor]/[model]
770
- // for example: "claude-3-5-sonnet" should become "anthropic/claude-3-5-sonnet"
771
- // but for now, we want to keep the old behavior
772
- // so we remove the "anthropic/" prefix if it exists
773
- if ( requestParams.model && requestParams.model.startsWith('anthropic/') ) {
774
- requestParams.model = requestParams.model.replace('anthropic/', '');
775
- }
776
-
777
- // convert to the correct model name if necessary
778
- if ( requestParams.model === 'claude-3-5-sonnet' ) {
779
- requestParams.model = 'claude-3-5-sonnet-latest';
780
- }
781
- if ( requestParams.model === 'claude-3-7-sonnet' || requestParams.model === 'claude' ) {
782
- requestParams.model = 'claude-3-7-sonnet-latest';
783
- }
784
- if ( requestParams.model === 'claude-sonnet-4' || requestParams.model === 'claude-sonnet-4-latest' ) {
785
- requestParams.model = 'claude-sonnet-4-20250514';
786
- }
787
- if ( requestParams.model === 'claude-opus-4' || requestParams.model === 'claude-opus-4-latest' ) {
788
- requestParams.model = 'claude-opus-4-20250514';
789
- }
790
- if ( requestParams.model === 'mistral' ) {
791
- requestParams.model = 'mistral-large-latest';
792
- }
793
- if ( requestParams.model === 'groq' ) {
794
- requestParams.model = 'llama3-8b-8192';
795
- }
796
- if ( requestParams.model === 'deepseek' ) {
797
- requestParams.model = 'deepseek-chat';
798
- }
799
-
800
- // o1-mini to openrouter:openai/o1-mini
801
- if ( requestParams.model === 'o1-mini' ) {
802
- requestParams.model = 'openrouter:openai/o1-mini';
803
- }
804
-
805
- // if a model is prepended with "openai/", remove it
806
- if ( requestParams.model && requestParams.model.startsWith('openai/') ) {
807
- requestParams.model = requestParams.model.replace('openai/', '');
808
- driver = 'openai-completion';
809
- }
810
- // For the following providers, we need to prepend "openrouter:" to the model name so that the backend driver can handle it
811
- if (
812
- requestParams.model.startsWith('agentica-org/') ||
813
- requestParams.model.startsWith('ai21/') ||
814
- requestParams.model.startsWith('aion-labs/') ||
815
- requestParams.model.startsWith('alfredpros/') ||
816
- requestParams.model.startsWith('allenai/') ||
817
- requestParams.model.startsWith('alpindale/') ||
818
- requestParams.model.startsWith('amazon/') ||
819
- requestParams.model.startsWith('anthracite-org/') ||
820
- requestParams.model.startsWith('arcee-ai/') ||
821
- requestParams.model.startsWith('arliai/') ||
822
- requestParams.model.startsWith('baidu/') ||
823
- requestParams.model.startsWith('bytedance/') ||
824
- requestParams.model.startsWith('cognitivecomputations/') ||
825
- requestParams.model.startsWith('cohere/') ||
826
- requestParams.model.startsWith('deepseek/') ||
827
- requestParams.model.startsWith('eleutherai/') ||
828
- requestParams.model.startsWith('google/') ||
829
- requestParams.model.startsWith('gryphe/') ||
830
- requestParams.model.startsWith('inception/') ||
831
- requestParams.model.startsWith('infermatic/') ||
832
- requestParams.model.startsWith('liquid/') ||
833
- requestParams.model.startsWith('mancer/') ||
834
- requestParams.model.startsWith('meta-llama/') ||
835
- requestParams.model.startsWith('microsoft/') ||
836
- requestParams.model.startsWith('minimax/') ||
837
- requestParams.model.startsWith('mistralai/') ||
838
- requestParams.model.startsWith('moonshotai/') ||
839
- requestParams.model.startsWith('morph/') ||
840
- requestParams.model.startsWith('neversleep/') ||
841
- requestParams.model.startsWith('nousresearch/') ||
842
- requestParams.model.startsWith('nvidia/') ||
843
- requestParams.model.startsWith('openrouter/') ||
844
- requestParams.model.startsWith('perplexity/') ||
845
- requestParams.model.startsWith('pygmalionai/') ||
846
- requestParams.model.startsWith('qwen/') ||
847
- requestParams.model.startsWith('raifle/') ||
848
- requestParams.model.startsWith('rekaai/') ||
849
- requestParams.model.startsWith('sao10k/') ||
850
- requestParams.model.startsWith('sarvamai/') ||
851
- requestParams.model.startsWith('scb10x/') ||
852
- requestParams.model.startsWith('shisa-ai/') ||
853
- requestParams.model.startsWith('sophosympatheia/') ||
854
- requestParams.model.startsWith('switchpoint/') ||
855
- requestParams.model.startsWith('tencent/') ||
856
- requestParams.model.startsWith('thedrummer/') ||
857
- requestParams.model.startsWith('thudm/') ||
858
- requestParams.model.startsWith('tngtech/') ||
859
- requestParams.model.startsWith('undi95/') ||
860
- requestParams.model.startsWith('x-ai/') ||
861
- requestParams.model.startsWith('z-ai/')
862
- ) {
863
- requestParams.model = `openrouter:${ requestParams.model}`;
864
- }
865
-
866
- // map model to the appropriate driver
867
- if ( !requestParams.model || requestParams.model.startsWith('gpt-') ) {
868
- driver = 'openai-completion';
869
- } else if (
870
- requestParams.model.startsWith('claude-')
871
- ) {
872
- driver = 'claude';
873
- } else if ( requestParams.model === 'meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo' || requestParams.model === 'meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo' || requestParams.model === 'meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo' || requestParams.model === 'google/gemma-2-27b-it' ) {
874
- driver = 'together-ai';
875
- } else if ( requestParams.model.startsWith('mistral-') || requestParams.model.startsWith('codestral-') || requestParams.model.startsWith('pixtral-') || requestParams.model.startsWith('magistral-') || requestParams.model.startsWith('devstral-') || requestParams.model.startsWith('mistral-ocr-') || requestParams.model.startsWith('open-mistral-') ) {
876
- driver = 'mistral';
877
- } else if ( [
878
- 'distil-whisper-large-v3-en',
879
- 'gemma2-9b-it',
880
- 'gemma-7b-it',
881
- 'llama-3.1-70b-versatile',
882
- 'llama-3.1-8b-instant',
883
- 'llama3-70b-8192',
884
- 'llama3-8b-8192',
885
- 'llama3-groq-70b-8192-tool-use-preview',
886
- 'llama3-groq-8b-8192-tool-use-preview',
887
- 'llama-guard-3-8b',
888
- 'mixtral-8x7b-32768',
889
- 'whisper-large-v3',
890
- ].includes(requestParams.model) ) {
891
- driver = 'groq';
892
- } else if ( requestParams.model === 'grok-beta' ) {
893
- driver = 'xai';
894
- }
895
- else if ( requestParams.model.startsWith('grok-') ) {
896
- driver = 'openrouter';
897
- }
898
- else if (
899
- requestParams.model === 'deepseek-chat' ||
900
- requestParams.model === 'deepseek-reasoner'
901
- ) {
902
- driver = 'deepseek';
903
- }
904
- else if (
905
- requestParams.model === 'gemini-1.5-flash' ||
906
- requestParams.model === 'gemini-2.0-flash' ||
907
- requestParams.model === 'gemini-2.5-flash' ||
908
- requestParams.model === 'gemini-2.5-flash-lite' ||
909
- requestParams.model === 'gemini-2.0-flash-lite' ||
910
- requestParams.model === 'gemini-3-pro-preview' ||
911
- requestParams.model === 'gemini-2.5-pro'
912
- ) {
913
- driver = 'gemini';
914
- }
915
- else if ( requestParams.model.startsWith('openrouter:') ) {
916
- driver = 'openrouter';
917
- }
918
- else if ( requestParams.model.startsWith('ollama:') ) {
919
- driver = 'ollama';
920
- }
921
-
922
742
  // stream flag from userParams
923
743
  if ( userParams.stream !== undefined && typeof userParams.stream === 'boolean' ) {
924
744
  requestParams.stream = userParams.stream;
@@ -1020,27 +840,11 @@ class AI {
1020
840
  }
1021
841
 
1022
842
  const driverHint = typeof options.driver === 'string' ? options.driver : undefined;
1023
- const providerRaw = typeof options.provider === 'string'
1024
- ? options.provider
1025
- : (typeof options.service === 'string' ? options.service : undefined);
1026
- const providerHint = typeof providerRaw === 'string' ? providerRaw.toLowerCase() : undefined;
1027
- const modelLower = typeof options.model === 'string' ? options.model.toLowerCase() : '';
1028
-
1029
- const looksLikeTogetherModel =
1030
- typeof options.model === 'string' &&
1031
- (TOGETHER_IMAGE_MODEL_PREFIXES.some(prefix => modelLower.startsWith(prefix)) ||
1032
- TOGETHER_IMAGE_MODEL_KEYWORDS.some(keyword => modelLower.includes(keyword)));
1033
843
 
1034
844
  if ( driverHint ) {
1035
845
  AIService = driverHint;
1036
- } else if ( providerHint === 'gemini' ) {
1037
- AIService = 'gemini-image-generation';
1038
- } else if ( providerHint === 'together' || providerHint === 'together-ai' ) {
1039
- AIService = 'together-image-generation';
1040
- } else if (options.model === 'gemini-2.5-flash-image-preview' || options.model === "gemini-3-pro-image-preview" ) {
1041
- AIService = 'gemini-image-generation';
1042
- } else if ( looksLikeTogetherModel ) {
1043
- AIService = 'together-image-generation';
846
+ } else {
847
+ AIService = 'ai-image';
1044
848
  }
1045
849
  // Call the original chat.complete method
1046
850
  return await utils.make_driver_method(['prompt'], 'puter-image-generation', AIService, 'generate', {
@@ -9,10 +9,11 @@ class Apps {
9
9
  * @param {string} APIOrigin - Origin of the API server. Used to build the API endpoint URLs.
10
10
  * @param {string} appID - ID of the app to use.
11
11
  */
12
- constructor (context) {
13
- this.authToken = context.authToken;
14
- this.APIOrigin = context.APIOrigin;
15
- this.appID = context.appID;
12
+ constructor (puter) {
13
+ this.puter = puter;
14
+ this.authToken = puter.authToken;
15
+ this.APIOrigin = puter.APIOrigin;
16
+ this.appID = puter.appID;
16
17
  }
17
18
 
18
19
  /**
@@ -212,4 +213,4 @@ class Apps {
212
213
  };
213
214
  }
214
215
 
215
- export default Apps;
216
+ export default Apps;
@@ -13,10 +13,11 @@ class Auth {
13
13
  * @param {string} APIOrigin - Origin of the API server. Used to build the API endpoint URLs.
14
14
  * @param {string} appID - ID of the app to use.
15
15
  */
16
- constructor (context) {
17
- this.authToken = context.authToken;
18
- this.APIOrigin = context.APIOrigin;
19
- this.appID = context.appID;
16
+ constructor (puter) {
17
+ this.puter = puter;
18
+ this.authToken = puter.authToken;
19
+ this.APIOrigin = puter.APIOrigin;
20
+ this.appID = puter.appID;
20
21
  }
21
22
 
22
23
  /**
@@ -291,4 +292,4 @@ class Auth {
291
292
  }
292
293
  }
293
294
 
294
- export default Auth;
295
+ export default Auth;