@moxxy/agent 0.2.1 → 0.2.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAK/C,MAAM,WAAW,qBAAqB;IACpC;oDACgD;IAChD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,gFAAgF;IAChF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,mBAAoB,SAAQ,qBAAqB;IAChE,gFAAgF;IAChF,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAOD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,GAAE,mBAAwB,GAAG,WAAW,CAYxE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,GAAE,qBAA0B,GAAG,WAAW,CAW7E;AAGD,OAAO,EACL,UAAU,EACV,KAAK,KAAK,EACV,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,UAAU,EACf,KAAK,MAAM,EACX,KAAK,OAAO,EACZ,KAAK,kBAAkB,GACxB,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAK/C,MAAM,WAAW,qBAAqB;IACpC;oDACgD;IAChD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,gFAAgF;IAChF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,mBAAoB,SAAQ,qBAAqB;IAChE,gFAAgF;IAChF,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAmBD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,GAAE,mBAAwB,GAAG,WAAW,CAYxE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,GAAE,qBAA0B,GAAG,WAAW,CAW7E;AAGD,OAAO,EACL,UAAU,EACV,KAAK,KAAK,EACV,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,UAAU,EACf,KAAK,MAAM,EACX,KAAK,OAAO,EACZ,KAAK,kBAAkB,GACxB,MAAM,aAAa,CAAC"}
package/dist/index.js CHANGED
@@ -19,9 +19,17 @@
19
19
  import defaultModePlugin from '@moxxy/mode-default';
20
20
  import openaiPlugin from '@moxxy/plugin-provider-openai';
21
21
  import anthropicPlugin from '@moxxy/plugin-provider-anthropic';
22
- /** Drop `undefined` config fields so they don't override provider defaults. */
22
+ /**
23
+ * Drop absent config fields so they don't override provider defaults.
24
+ * Blank strings count as absent: an unset-but-present env var (`OPENAI_API_KEY=`,
25
+ * or a templated `.env` leaving `OPENAI_API_KEY=" "`) would otherwise freeze
26
+ * `apiKey: ' '`, defeating the provider's own env fallback (`'…' ?? x`
27
+ * short-circuits to the blank string) and turning a clear no-key path into an
28
+ * opaque 401 at the first turn. Trimming here keeps the no-key path live and
29
+ * mirrors the providers' own `key.trim()` validation.
30
+ */
23
31
  function clean(config) {
24
- return Object.fromEntries(Object.entries(config).filter(([, v]) => v !== undefined));
32
+ return Object.fromEntries(Object.entries(config).filter(([, v]) => v !== undefined && !(typeof v === 'string' && v.trim() === '')));
25
33
  }
26
34
  /**
27
35
  * One-shop OpenAI (and OpenAI-compatible) preset: the default loop + the OpenAI
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,iBAAiB,MAAM,qBAAqB,CAAC;AACpD,OAAO,YAAY,MAAM,+BAA+B,CAAC;AACzD,OAAO,eAAe,MAAM,kCAAkC,CAAC;AAe/D,+EAA+E;AAC/E,SAAS,KAAK,CAAC,MAA+B;IAC5C,OAAO,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC;AACvF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,OAA4B,EAAE;IACzD,OAAO;QACL,OAAO,EAAE,CAAC,iBAAiB,EAAE,YAAY,CAAC;QAC1C,QAAQ,EAAE;YACR,IAAI,EAAE,QAAQ;YACd,MAAM,EAAE,KAAK,CAAC;gBACZ,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc;gBACjD,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,OAAO,EAAE,IAAI,CAAC,OAAO;aACtB,CAAC;SACH;KACF,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,OAA8B,EAAE;IAC9D,OAAO;QACL,OAAO,EAAE,CAAC,iBAAiB,EAAE,eAAe,CAAC;QAC7C,QAAQ,EAAE;YACR,IAAI,EAAE,WAAW;YACjB,MAAM,EAAE,KAAK,CAAC;gBACZ,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB;gBACpD,KAAK,EAAE,IAAI,CAAC,KAAK;aAClB,CAAC;SACH;KACF,CAAC;AACJ,CAAC;AAED,4EAA4E;AAC5E,OAAO,EACL,UAAU,GAQX,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,iBAAiB,MAAM,qBAAqB,CAAC;AACpD,OAAO,YAAY,MAAM,+BAA+B,CAAC;AACzD,OAAO,eAAe,MAAM,kCAAkC,CAAC;AAe/D;;;;;;;;GAQG;AACH,SAAS,KAAK,CAAC,MAA+B;IAC5C,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,CAC3B,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAC1E,CACF,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,OAA4B,EAAE;IACzD,OAAO;QACL,OAAO,EAAE,CAAC,iBAAiB,EAAE,YAAY,CAAC;QAC1C,QAAQ,EAAE;YACR,IAAI,EAAE,QAAQ;YACd,MAAM,EAAE,KAAK,CAAC;gBACZ,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc;gBACjD,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,OAAO,EAAE,IAAI,CAAC,OAAO;aACtB,CAAC;SACH;KACF,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,OAA8B,EAAE;IAC9D,OAAO;QACL,OAAO,EAAE,CAAC,iBAAiB,EAAE,eAAe,CAAC;QAC7C,QAAQ,EAAE;YACR,IAAI,EAAE,WAAW;YACjB,MAAM,EAAE,KAAK,CAAC;gBACZ,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB;gBACpD,KAAK,EAAE,IAAI,CAAC,KAAK;aAClB,CAAC;SACH;KACF,CAAC;AACJ,CAAC;AAED,4EAA4E;AAC5E,OAAO,EACL,UAAU,GAQX,MAAM,aAAa,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moxxy/agent",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Batteries-included entry to moxxy: one install + one call to run an agent. Bundles @moxxy/core, the default loop, and the OpenAI + Anthropic providers behind drop-in presets — `setupAgent(openaiPreset({ apiKey }))`.",
5
5
  "keywords": [
6
6
  "moxxy",
@@ -39,11 +39,11 @@
39
39
  "src"
40
40
  ],
41
41
  "dependencies": {
42
- "@moxxy/mode-default": "0.1.0",
43
- "@moxxy/core": "0.4.0",
44
- "@moxxy/sdk": "0.15.0",
45
- "@moxxy/plugin-provider-openai": "0.1.0",
46
- "@moxxy/plugin-provider-anthropic": "0.2.0"
42
+ "@moxxy/core": "0.5.1",
43
+ "@moxxy/mode-default": "0.1.1",
44
+ "@moxxy/sdk": "0.15.1",
45
+ "@moxxy/plugin-provider-openai": "0.1.1",
46
+ "@moxxy/plugin-provider-anthropic": "0.2.1"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@types/node": "^22.10.0",
package/src/index.test.ts CHANGED
@@ -3,9 +3,12 @@ import { afterEach, describe, expect, it } from 'vitest';
3
3
  import { setupAgent, openaiPreset, anthropicPreset } from './index.js';
4
4
 
5
5
  const ORIGINAL_OPENAI = process.env.OPENAI_API_KEY;
6
+ const ORIGINAL_ANTHROPIC = process.env.ANTHROPIC_API_KEY;
6
7
  afterEach(() => {
7
8
  if (ORIGINAL_OPENAI === undefined) delete process.env.OPENAI_API_KEY;
8
9
  else process.env.OPENAI_API_KEY = ORIGINAL_OPENAI;
10
+ if (ORIGINAL_ANTHROPIC === undefined) delete process.env.ANTHROPIC_API_KEY;
11
+ else process.env.ANTHROPIC_API_KEY = ORIGINAL_ANTHROPIC;
9
12
  });
10
13
 
11
14
  describe('@moxxy/agent presets', () => {
@@ -39,4 +42,59 @@ describe('@moxxy/agent presets', () => {
39
42
  expect(openaiPreset().provider?.config?.apiKey).toBe('env-key');
40
43
  expect(openaiPreset({ apiKey: 'explicit' }).provider?.config?.apiKey).toBe('explicit');
41
44
  });
45
+
46
+ it('passes baseURL and model through to provider.config', () => {
47
+ const config = openaiPreset({ apiKey: 'sk-test', model: 'x', baseURL: 'y' }).provider?.config;
48
+ expect(config?.model).toBe('x');
49
+ expect(config?.baseURL).toBe('y');
50
+ });
51
+
52
+ it('omits absent fields entirely (not as undefined) so provider defaults win', () => {
53
+ delete process.env.OPENAI_API_KEY;
54
+ const config = openaiPreset().provider?.config ?? {};
55
+ // Absent keys must not exist at all — a present `undefined`/`''` would
56
+ // override the provider's own catalog/env fallback.
57
+ expect('model' in config).toBe(false);
58
+ expect('baseURL' in config).toBe(false);
59
+ expect('apiKey' in config).toBe(false);
60
+ });
61
+
62
+ it('treats an empty-string env var as absent so the provider fallback survives', () => {
63
+ process.env.OPENAI_API_KEY = '';
64
+ const config = openaiPreset().provider?.config ?? {};
65
+ // `OPENAI_API_KEY=` must not freeze apiKey:'' (which `'' ?? x` would keep,
66
+ // defeating the provider's lazy env fallback and yielding an opaque 401).
67
+ expect('apiKey' in config).toBe(false);
68
+ });
69
+
70
+ it('treats an explicit empty-string apiKey/model/baseURL as absent', () => {
71
+ delete process.env.OPENAI_API_KEY;
72
+ const config = openaiPreset({ apiKey: '', model: '', baseURL: '' }).provider?.config ?? {};
73
+ expect('apiKey' in config).toBe(false);
74
+ expect('model' in config).toBe(false);
75
+ expect('baseURL' in config).toBe(false);
76
+ });
77
+
78
+ it('treats a whitespace-only apiKey/env as absent so the provider fallback survives', () => {
79
+ // A templated/whitespace env var (`OPENAI_API_KEY=" "`) or an explicit blank
80
+ // key must NOT freeze a blank apiKey — `' ' ?? x` would short-circuit and hand
81
+ // the SDK a non-credential, yielding an opaque 401 instead of the no-key path.
82
+ process.env.OPENAI_API_KEY = ' ';
83
+ expect('apiKey' in (openaiPreset().provider?.config ?? {})).toBe(false);
84
+ delete process.env.OPENAI_API_KEY;
85
+ const cfg = openaiPreset({ apiKey: ' \t\n', model: ' ', baseURL: '\t' }).provider?.config ?? {};
86
+ expect('apiKey' in cfg).toBe(false);
87
+ expect('model' in cfg).toBe(false);
88
+ expect('baseURL' in cfg).toBe(false);
89
+ });
90
+
91
+ it('anthropicPreset: env fallback, and blank apiKey/env treated as absent', () => {
92
+ process.env.ANTHROPIC_API_KEY = 'env-ant';
93
+ expect(anthropicPreset().provider?.config?.apiKey).toBe('env-ant');
94
+ expect(anthropicPreset({ apiKey: 'explicit' }).provider?.config?.apiKey).toBe('explicit');
95
+ process.env.ANTHROPIC_API_KEY = ' ';
96
+ expect('apiKey' in (anthropicPreset().provider?.config ?? {})).toBe(false);
97
+ delete process.env.ANTHROPIC_API_KEY;
98
+ expect('apiKey' in (anthropicPreset({ apiKey: '' }).provider?.config ?? {})).toBe(false);
99
+ });
42
100
  });
package/src/index.ts CHANGED
@@ -35,9 +35,21 @@ export interface OpenAIPresetOptions extends ProviderPresetOptions {
35
35
  readonly baseURL?: string;
36
36
  }
37
37
 
38
- /** Drop `undefined` config fields so they don't override provider defaults. */
38
+ /**
39
+ * Drop absent config fields so they don't override provider defaults.
40
+ * Blank strings count as absent: an unset-but-present env var (`OPENAI_API_KEY=`,
41
+ * or a templated `.env` leaving `OPENAI_API_KEY=" "`) would otherwise freeze
42
+ * `apiKey: ' '`, defeating the provider's own env fallback (`'…' ?? x`
43
+ * short-circuits to the blank string) and turning a clear no-key path into an
44
+ * opaque 401 at the first turn. Trimming here keeps the no-key path live and
45
+ * mirrors the providers' own `key.trim()` validation.
46
+ */
39
47
  function clean(config: Record<string, unknown>): Record<string, unknown> {
40
- return Object.fromEntries(Object.entries(config).filter(([, v]) => v !== undefined));
48
+ return Object.fromEntries(
49
+ Object.entries(config).filter(
50
+ ([, v]) => v !== undefined && !(typeof v === 'string' && v.trim() === ''),
51
+ ),
52
+ );
41
53
  }
42
54
 
43
55
  /**