@whittlelabs/sifter 0.37.0 → 0.38.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.
Files changed (3) hide show
  1. package/bin.js +53 -26
  2. package/bin.js.map +4 -4
  3. package/package.json +1 -1
package/bin.js CHANGED
@@ -10632,6 +10632,26 @@ var require_workspace_telemetry = __commonJS({
10632
10632
  }
10633
10633
  });
10634
10634
 
10635
+ // ../../packages/shuttle/dist/executors/model-providers.js
10636
+ var require_model_providers = __commonJS({
10637
+ "../../packages/shuttle/dist/executors/model-providers.js"(exports2) {
10638
+ "use strict";
10639
+ Object.defineProperty(exports2, "__esModule", { value: true });
10640
+ exports2.MODEL_PROVIDER_ENV = void 0;
10641
+ exports2.requireModelProvider = requireModelProvider;
10642
+ exports2.MODEL_PROVIDER_ENV = {
10643
+ anthropic: "ANTHROPIC_API_KEY"
10644
+ };
10645
+ function requireModelProvider(executor, accepts, credential) {
10646
+ const provider = credential.provider;
10647
+ if (!provider || !accepts.includes(provider)) {
10648
+ throw new Error(`The ${executor} executor runs ${accepts.join(" or ")} models, and this customer's model key is ${provider ? `for ${provider}` : "for an unstated provider"}.`);
10649
+ }
10650
+ return provider;
10651
+ }
10652
+ }
10653
+ });
10654
+
10635
10655
  // ../../packages/shuttle/dist/executors/cli-version.js
10636
10656
  var require_cli_version = __commonJS({
10637
10657
  "../../packages/shuttle/dist/executors/cli-version.js"(exports2) {
@@ -10736,6 +10756,8 @@ var require_claude_code = __commonJS({
10736
10756
  var json_answer_1 = require_json_answer();
10737
10757
  var models_1 = require_models();
10738
10758
  var workspace_telemetry_1 = require_workspace_telemetry();
10759
+ var model_providers_1 = require_model_providers();
10760
+ var CLAUDE_CODE_PROVIDERS = ["anthropic"];
10739
10761
  var cli_version_1 = require_cli_version();
10740
10762
  var apply_1 = require_apply();
10741
10763
  var version_check_1 = require_version_check();
@@ -10849,18 +10871,22 @@ var require_claude_code = __commonJS({
10849
10871
  async execute(dispatch, signal, ctx) {
10850
10872
  const { prompt, spec } = (0, loom_1.renderPromptExecution)(dispatch.inputs);
10851
10873
  const workspace = ctx?.workspace ?? null;
10852
- let modelKey = null;
10874
+ let modelEnv = null;
10853
10875
  if (ctx?.credentials) {
10854
10876
  const hints = (0, loom_1.pickProviderHints)(spec, "anthropic-api");
10855
10877
  const customerId = typeof hints.customerId === "string" ? hints.customerId : void 0;
10856
10878
  if (!customerId) {
10857
10879
  throw new Error("claude-code dynamic-key mode requires providerHints.anthropicApi.customerId on every job");
10858
10880
  }
10859
- modelKey = await ctx.credentials.reveal({ name: "managed-model-key", principal: customerId });
10881
+ const credential = await ctx.credentials.reveal({ name: "model-credential", principal: customerId });
10882
+ if (credential) {
10883
+ const provider = (0, model_providers_1.requireModelProvider)("claude-code", CLAUDE_CODE_PROVIDERS, credential);
10884
+ modelEnv = { [model_providers_1.MODEL_PROVIDER_ENV[provider]]: credential.secret };
10885
+ }
10860
10886
  }
10861
10887
  let jobScratch = null;
10862
10888
  let configDir;
10863
- if (modelKey) {
10889
+ if (modelEnv) {
10864
10890
  jobScratch = await fs_1.promises.mkdtemp(path_1.default.join(os_1.default.tmpdir(), "shuttle-cc-"));
10865
10891
  configDir = path_1.default.join(jobScratch, "claude-config");
10866
10892
  await fs_1.promises.mkdir(configDir);
@@ -10869,7 +10895,7 @@ var require_claude_code = __commonJS({
10869
10895
  let promptOnlyScratch = null;
10870
10896
  const reporter = spec.progressChannel && ctx?.reportProgress ? new progress_1.ProgressReporter((frames) => ctx.reportProgress(spec.progressChannel, frames)) : null;
10871
10897
  try {
10872
- const childEnv = buildChildEnv(modelKey, configDir);
10898
+ const childEnv = buildChildEnv(modelEnv, configDir);
10873
10899
  const claudeHints = (0, loom_1.pickProviderHints)(spec, "claude-code");
10874
10900
  const hintedModel = typeof claudeHints.model === "string" && claudeHints.model.length > 0 ? claudeHints.model : void 0;
10875
10901
  const effort = (0, models_1.hintedEffort)(claudeHints);
@@ -10890,7 +10916,7 @@ var require_claude_code = __commonJS({
10890
10916
  // Local mode is the operator's own login: a failure of THAT is the
10891
10917
  // machine's, and the runner pauses on it. With a revealed key it is one
10892
10918
  // customer's, and only their job fails.
10893
- modelKey === null,
10919
+ modelEnv === null,
10894
10920
  effort
10895
10921
  );
10896
10922
  if (workspace) {
@@ -11163,8 +11189,8 @@ var require_claude_code = __commonJS({
11163
11189
  }
11164
11190
  return scoped;
11165
11191
  }
11166
- function buildChildEnv(modelKey, configDir) {
11167
- if (!modelKey && !configDir)
11192
+ function buildChildEnv(modelEnv, configDir) {
11193
+ if (!modelEnv && !configDir)
11168
11194
  return void 0;
11169
11195
  const env = {};
11170
11196
  for (const name of HOSTED_ENV_PASSTHROUGH) {
@@ -11173,7 +11199,7 @@ var require_claude_code = __commonJS({
11173
11199
  }
11174
11200
  return {
11175
11201
  ...env,
11176
- ...modelKey ? { ANTHROPIC_API_KEY: modelKey } : {},
11202
+ ...modelEnv ?? {},
11177
11203
  ...configDir ? { CLAUDE_CONFIG_DIR: configDir } : {}
11178
11204
  };
11179
11205
  }
@@ -12708,18 +12734,16 @@ var require_client = __commonJS({
12708
12734
  }
12709
12735
  // ── Managed Sifter ──────────────────────────────────────────────
12710
12736
  /**
12711
- * Reveal a hosted-Sifter customer's plaintext Anthropic API key for
12712
- * one dispatch. Service-token only; requires the
12713
- * `keep:managed-sifter-key-material:read` scope, granted only to the
12714
- * `whittle-hosted-sifter` service identity.
12737
+ * Reveal a person's model-provider key for one hosted dispatch, with the
12738
+ * provider it is for (ADR-0127). Service-token only; requires
12739
+ * `keep:managed-sifter-key-material:read` at that user, granted only to the
12740
+ * `whittle-hosted-sifter` service identity. Keep refuses unless the person
12741
+ * holds the hosted tier. Name `provider` when they may hold more than one.
12715
12742
  *
12716
- * Callers must use the returned key for a single Anthropic request
12717
- * and drop it from memory afterwards. Keep stamps `last_used_at` on
12718
- * every call and is the audit-of-record for who decrypted whose key
12719
- * when.
12743
+ * Use the credential for the dispatch and drop it from memory afterwards.
12720
12744
  */
12721
- async revealManagedSifterKey(userId) {
12722
- return this.request("POST", `/api/managed-sifters/${encodeURIComponent(userId)}/reveal-key`);
12745
+ async revealModelCredential(userId, options = {}) {
12746
+ return this.request("POST", `/api/users/${encodeURIComponent(userId)}/model-credential`, options.provider ? { provider: options.provider } : {});
12723
12747
  }
12724
12748
  /**
12725
12749
  * Read a user's hosted-Sifter opt-in status. Returns `{enabled:
@@ -13358,6 +13382,7 @@ var require_anthropic_api = __commonJS({
13358
13382
  var keep_1 = require_dist2();
13359
13383
  var env_ref_1 = require_env_ref();
13360
13384
  var validate_output_1 = require_validate_output();
13385
+ var model_providers_1 = require_model_providers();
13361
13386
  var types_1 = require_types2();
13362
13387
  var models_1 = require_models();
13363
13388
  var DEFAULT_BASE_URL = "https://api.anthropic.com/v1/messages";
@@ -13605,8 +13630,9 @@ var require_anthropic_api = __commonJS({
13605
13630
  throw new Error("AnthropicApiExecutor dynamic-key mode failed to exchange a Keep service token. Check KEEP_CLIENT_ID / KEEP_CLIENT_SECRET.");
13606
13631
  }
13607
13632
  const keep = keepClientFactory({ baseUrl: keepApiUrl, serviceToken });
13608
- const reveal = await keep.revealManagedSifterKey(customerId);
13609
- return reveal.apiKey;
13633
+ const reveal = await keep.revealModelCredential(customerId);
13634
+ (0, model_providers_1.requireModelProvider)("anthropic-api", ["anthropic"], { secret: reveal.credential, provider: reveal.provider });
13635
+ return reveal.credential;
13610
13636
  };
13611
13637
  }
13612
13638
  function safeJsonParse(s) {
@@ -22204,6 +22230,7 @@ var require_client2 = __commonJS({
22204
22230
  const body = {
22205
22231
  jobPoolId,
22206
22232
  title: options.title,
22233
+ progressChannel: options.progressChannel,
22207
22234
  instructions: options.instructions,
22208
22235
  maxAttempts: options.maxAttempts,
22209
22236
  deadlineDuration: options.deadlineDuration,
@@ -26641,7 +26668,7 @@ var require_git = __commonJS({
26641
26668
  let gitToken = null;
26642
26669
  if (ref && typeof ref.name === "string" && typeof ref.principal === "string" && options.credentials) {
26643
26670
  try {
26644
- gitToken = await options.credentials.reveal(ref);
26671
+ gitToken = (await options.credentials.reveal(ref))?.secret ?? null;
26645
26672
  } catch {
26646
26673
  gitToken = null;
26647
26674
  }
@@ -27248,14 +27275,14 @@ var require_registry2 = __commonJS({
27248
27275
  function getCredentialResolver(name) {
27249
27276
  return resolvers.get(name);
27250
27277
  }
27251
- registerCredentialResolver("managed-model-key", async (keep, principal) => {
27252
- const reveal = await keep.revealManagedSifterKey(principal);
27253
- return reveal.apiKey;
27278
+ registerCredentialResolver("model-credential", async (keep, principal) => {
27279
+ const reveal = await keep.revealModelCredential(principal);
27280
+ return { secret: reveal.credential, provider: reveal.provider };
27254
27281
  });
27255
27282
  registerCredentialResolver("github-user-token", async (keep, principal) => {
27256
27283
  try {
27257
27284
  const reveal = await keep.getUserGithubToken(principal);
27258
- return reveal.access_token;
27285
+ return { secret: reveal.access_token, provider: "github" };
27259
27286
  } catch {
27260
27287
  return null;
27261
27288
  }
@@ -29387,7 +29414,7 @@ var import_path = require("path");
29387
29414
  var import_promises = require("fs/promises");
29388
29415
  var import_yaml = __toESM(require_dist3());
29389
29416
  var import_shuttle = __toESM(require_dist5());
29390
- var buildVersion = true ? "0.37.0" : pkg.version;
29417
+ var buildVersion = true ? "0.38.0" : pkg.version;
29391
29418
  var AGENT_EXECUTORS = ["claude-code", "codex", "copilot"];
29392
29419
  var sifterBrand = {
29393
29420
  product: {