@noetic-tools/core 1.3.0 → 2.0.0

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.
@@ -61,6 +61,29 @@ interface AgentHarnessOpts<TParams extends Record<string, unknown> = Record<stri
61
61
  /** @internal Test-only escape hatch to inject a mock callModel implementation. */
62
62
  _testCallModel?: (request: CallModelRequest) => Promise<LLMResponse>;
63
63
  }
64
+ /** Env vars consulted when resolving the LLM client (read defensively so the
65
+ * harness also works in runtimes without a `process` global, e.g. the browser). */
66
+ interface LlmEnv {
67
+ noeticApiKey?: string;
68
+ noeticBaseUrl?: string;
69
+ openrouterApiKey?: string;
70
+ }
71
+ /** @public Effective client options resolved from config + environment. */
72
+ export interface ResolvedLlmClient {
73
+ apiKey: string;
74
+ /** Undefined means "use the SDK's default OpenRouter base URL". */
75
+ serverURL?: string;
76
+ cache: boolean;
77
+ }
78
+ /**
79
+ * Resolve the effective LLM client options from the provider config + environment.
80
+ * Defaults to the Noetic platform (`provider: 'noetic'`): the `'noetic'` provider
81
+ * authenticates with `NOETIC_API_KEY` and targets the Noetic platform base URL,
82
+ * while `'openrouter'` authenticates with `OPENROUTER_API_KEY` and uses the SDK's
83
+ * default OpenRouter endpoint. Returns undefined when no API key is available.
84
+ * Exported for testing.
85
+ */
86
+ export declare function resolveLlmClient(config: LlmProviderConfig | undefined, env: LlmEnv): ResolvedLlmClient | undefined;
64
87
  /**
65
88
  * Default agent harness for executing agent steps with built-in channel, memory, and trace support.
66
89
  * Provides channel store, memory layer lifecycle, and trace export with no external dependencies.
@@ -36,23 +36,62 @@ function resolveContextCwdState(rootCwdState, parent, cwdInit) {
36
36
  }
37
37
  return rootCwdState;
38
38
  }
39
- function createClient(config) {
39
+ /** The Noetic platform's OpenAI-Responses-compatible inference base URL. */
40
+ const NOETIC_DEFAULT_BASE_URL = 'https://platform.noetic.tools/v1';
41
+ function readLlmEnv() {
40
42
  const processValue = 'process' in globalThis ? globalThis.process : undefined;
41
- const envValue = typeof processValue === 'object' && processValue !== null && 'env' in processValue
43
+ const env = typeof processValue === 'object' && processValue !== null && 'env' in processValue
42
44
  ? processValue.env
43
45
  : undefined;
44
- const openRouterApiKey = typeof envValue === 'object' && envValue !== null && 'OPENROUTER_API_KEY' in envValue
45
- ? envValue.OPENROUTER_API_KEY
46
- : undefined;
47
- const apiKey = config?.apiKey ?? (typeof openRouterApiKey === 'string' ? openRouterApiKey : undefined);
46
+ if (typeof env !== 'object' || env === null) {
47
+ return {};
48
+ }
49
+ const str = (value) => typeof value === 'string' ? value : undefined;
50
+ return {
51
+ noeticApiKey: 'NOETIC_API_KEY' in env ? str(env.NOETIC_API_KEY) : undefined,
52
+ noeticBaseUrl: 'NOETIC_BASE_URL' in env ? str(env.NOETIC_BASE_URL) : undefined,
53
+ openrouterApiKey: 'OPENROUTER_API_KEY' in env ? str(env.OPENROUTER_API_KEY) : undefined,
54
+ };
55
+ }
56
+ /**
57
+ * Resolve the effective LLM client options from the provider config + environment.
58
+ * Defaults to the Noetic platform (`provider: 'noetic'`): the `'noetic'` provider
59
+ * authenticates with `NOETIC_API_KEY` and targets the Noetic platform base URL,
60
+ * while `'openrouter'` authenticates with `OPENROUTER_API_KEY` and uses the SDK's
61
+ * default OpenRouter endpoint. Returns undefined when no API key is available.
62
+ * Exported for testing.
63
+ */
64
+ export function resolveLlmClient(config, env) {
65
+ const provider = config?.provider ?? 'noetic';
66
+ const apiKey = config?.apiKey ?? (provider === 'noetic' ? env.noeticApiKey : env.openrouterApiKey);
48
67
  if (!apiKey) {
49
68
  return undefined;
50
69
  }
51
- if (config?.cache) {
52
- // Inject `X-OpenRouter-Cache: true` on every request so OpenRouter serves
70
+ const serverURL = provider === 'noetic'
71
+ ? (config?.baseUrl ?? env.noeticBaseUrl ?? NOETIC_DEFAULT_BASE_URL)
72
+ : config?.baseUrl;
73
+ return {
74
+ apiKey,
75
+ serverURL,
76
+ cache: config?.cache ?? false,
77
+ };
78
+ }
79
+ function createClient(config) {
80
+ const resolved = resolveLlmClient(config, readLlmEnv());
81
+ if (!resolved) {
82
+ return undefined;
83
+ }
84
+ const options = {
85
+ apiKey: resolved.apiKey,
86
+ };
87
+ if (resolved.serverURL) {
88
+ options.serverURL = resolved.serverURL;
89
+ }
90
+ if (resolved.cache) {
91
+ // Inject `X-OpenRouter-Cache: true` on every request so the upstream serves
53
92
  // identical model calls from cache without re-billing (deterministic re-runs).
54
93
  return new OpenRouter({
55
- apiKey,
94
+ ...options,
56
95
  hooks: {
57
96
  beforeRequest: (_ctx, request) => {
58
97
  request.headers.set('X-OpenRouter-Cache', 'true');
@@ -61,9 +100,7 @@ function createClient(config) {
61
100
  },
62
101
  });
63
102
  }
64
- return new OpenRouter({
65
- apiKey,
66
- });
103
+ return new OpenRouter(options);
67
104
  }
68
105
  //#region AgentHarness
69
106
  /**
@@ -317,7 +317,7 @@ export class AgentHarnessModelCaller {
317
317
  throw new NoeticConfigError({
318
318
  code: 'NO_LLM_PROVIDER',
319
319
  message: 'No LLM provider configured on this harness.',
320
- hint: 'Pass `llm: { provider: "openrouter", apiKey: "..." }` in constructor options or set OPENROUTER_API_KEY.',
320
+ hint: 'Pass `llm: { apiKey: "..." }` (defaults to the Noetic platform) or set NOETIC_API_KEY. For direct OpenRouter, use `llm: { provider: "openrouter", apiKey: "..." }` or set OPENROUTER_API_KEY.',
321
321
  });
322
322
  }
323
323
  async callModel(request) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noetic-tools/core",
3
- "version": "1.3.0",
3
+ "version": "2.0.0",
4
4
  "type": "module",
5
5
  "description": "Step primitives, interpreter, runtime, and memory layer contract for Noetic agents.",
6
6
  "license": "Apache-2.0",
@@ -67,7 +67,7 @@
67
67
  },
68
68
  "dependencies": {
69
69
  "@noetic-tools/memory": "^1.0.1",
70
- "@noetic-tools/types": "^1.0.3",
70
+ "@noetic-tools/types": "^1.1.0",
71
71
  "@openrouter/agent": "^0.6.0",
72
72
  "zod": "^4.0.0"
73
73
  },