@standardagents/builder 0.27.6 → 0.27.8-dev.b0d0355

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/dist/index.js CHANGED
@@ -893,12 +893,64 @@ var init_ProviderRegistry = __esm({
893
893
  init_factory();
894
894
  ProviderRegistryImpl = class {
895
895
  providerCache = /* @__PURE__ */ new Map();
896
+ /** Why the last thread-scoped resolution did (not) contribute user env,
897
+ * keyed by the env object handed back — surfaced in missing-variable
898
+ * errors so a silent user-env failure is diagnosable from the log. */
899
+ scopeDiagnostics = /* @__PURE__ */ new WeakMap();
896
900
  providerOverrideFn = null;
897
901
  providerOverrideRevision = 0;
898
902
  setProviderOverride(fn) {
899
903
  this.providerOverrideFn = fn;
900
904
  this.providerOverrideRevision += 1;
901
905
  }
906
+ /**
907
+ * The env a provider resolves against for a given execution, scoped to the
908
+ * THREAD rather than just the instance: thread env overrides win, then the
909
+ * thread OWNER's user env, then instance/Worker env. This is what makes
910
+ * per-user BYOK providers work — a credential a user installs in their own
911
+ * account env (e.g. an OAuth token a companion service rotates) is honored
912
+ * for that user's threads no matter which authorized actor plays the turn.
913
+ *
914
+ * Best-effort by design: a missing user id (super-admin/local threads) or
915
+ * an older AgentBuilder DO without user-env storage simply contributes
916
+ * nothing, leaving instance-env behavior untouched.
917
+ */
918
+ async buildThreadScopedEnv(state) {
919
+ const threadEnv = state.thread.metadata?.env ?? state.thread.metadata?.tenvs ?? null;
920
+ const userId = state.thread.metadata?.user_id ?? null;
921
+ let userEnv = null;
922
+ let diagnostic = userId ? "" : "no thread user_id";
923
+ if (userId) {
924
+ try {
925
+ const agentBuilderId = state.env.AGENT_BUILDER.idFromName("singleton");
926
+ const agentBuilder = state.env.AGENT_BUILDER.get(agentBuilderId);
927
+ if (typeof agentBuilder.getUserEnvEntries === "function") {
928
+ const entries = await agentBuilder.getUserEnvEntries(userId);
929
+ if (Array.isArray(entries) && entries.length > 0) {
930
+ userEnv = {};
931
+ for (const entry of entries) {
932
+ if (entry?.name) userEnv[entry.name] = entry.value;
933
+ }
934
+ diagnostic = `user env: ${Object.keys(userEnv).length} entries`;
935
+ } else {
936
+ diagnostic = `user env empty for ${userId} (entries: ${Array.isArray(entries) ? entries.length : typeof entries})`;
937
+ }
938
+ } else {
939
+ diagnostic = "singleton has no getUserEnvEntries";
940
+ }
941
+ } catch (error) {
942
+ diagnostic = `user env lookup failed: ${error instanceof Error ? error.message : String(error)}`;
943
+ console.warn("buildThreadScopedEnv:", diagnostic);
944
+ }
945
+ }
946
+ if (!userEnv && !threadEnv) {
947
+ this.scopeDiagnostics.set(state.env, diagnostic);
948
+ return state.env;
949
+ }
950
+ const merged = { ...state.env, ...userEnv ?? {}, ...threadEnv ?? {} };
951
+ this.scopeDiagnostics.set(merged, diagnostic);
952
+ return merged;
953
+ }
902
954
  /**
903
955
  * Get provider for a model.
904
956
  *
@@ -936,8 +988,9 @@ var init_ProviderRegistry = __esm({
936
988
  if (providerDefinition) {
937
989
  const resolved = resolveDefinedProviderConfig(providerDefinition, env);
938
990
  if (resolved.missing.length > 0) {
991
+ const scopeNote = this.scopeDiagnostics.get(env);
939
992
  throw new Error(
940
- `Missing required environment variables for provider '${providerName}': ${resolved.missing.join(", ")}.`
993
+ `Missing required environment variables for provider '${providerName}': ${resolved.missing.join(", ")}.` + (scopeNote ? ` [thread-scoped env: ${scopeNote}]` : "")
941
994
  );
942
995
  }
943
996
  const config = resolved.providerConfig;
@@ -1810,7 +1863,8 @@ var init_LLMRequest = __esm({
1810
1863
  */
1811
1864
  static async callModel(modelId, context, state, logId) {
1812
1865
  const { ProviderRegistry: ProviderRegistry2 } = await Promise.resolve().then(() => (init_providers(), providers_exports));
1813
- const { provider, modelName, modelDef, viaPlatform, platformProxyOrigin } = await ProviderRegistry2.getProvider(modelId, state.env, state.thread.instance);
1866
+ const providerEnv2 = await ProviderRegistry2.buildThreadScopedEnv(state);
1867
+ const { provider, modelName, modelDef, viaPlatform, platformProxyOrigin } = await ProviderRegistry2.getProvider(modelId, providerEnv2, state.thread.instance);
1814
1868
  const streamAbort = new AbortController();
1815
1869
  const parentSignal = state.abortController?.signal;
1816
1870
  let onParentAbort;