@whittlelabs/sifter 0.38.0 → 0.39.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 +73 -18
  2. package/bin.js.map +2 -2
  3. package/package.json +1 -1
package/bin.js CHANGED
@@ -9963,6 +9963,10 @@ var require_progress = __commonJS({
9963
9963
  textBuf = "";
9964
9964
  /** The last two characters of reasoning emitted since the last tool; null when none. */
9965
9965
  reasoningTail = null;
9966
+ /** A streamed block has begun and none of its text has been emitted yet. */
9967
+ blockStart = false;
9968
+ /** The open streamed block's trailing whitespace, held until text follows it. */
9969
+ heldSpace = "";
9966
9970
  timer = null;
9967
9971
  closed = false;
9968
9972
  flushMs;
@@ -9996,15 +10000,42 @@ var require_progress = __commonJS({
9996
10000
  const block = text.trim();
9997
10001
  if (this.closed || !block)
9998
10002
  return;
9999
- const tail = this.reasoningTail;
10000
- const gap = tail === null || tail.endsWith("\n\n") ? "" : tail.endsWith("\n") ? "\n" : "\n\n";
10001
- this.reasoning(gap + block);
10003
+ this.reasoning(this.gap() + block);
10004
+ }
10005
+ /**
10006
+ * A block of reasoning begins that will arrive in pieces through
10007
+ * `reasoningDelta`, as the model writes it. Set off and trimmed exactly as
10008
+ * `reasoningBlock` sets off and trims a whole one, so a streamed transcript
10009
+ * reads the same as one reported block by block; only its timing differs.
10010
+ */
10011
+ beginBlock() {
10012
+ this.blockStart = true;
10013
+ this.heldSpace = "";
10014
+ }
10015
+ /** The next piece of the block `beginBlock` opened. */
10016
+ reasoningDelta(text) {
10017
+ if (this.closed || !text)
10018
+ return;
10019
+ let body = this.heldSpace + text;
10020
+ if (this.blockStart)
10021
+ body = body.trimStart();
10022
+ const kept = body.trimEnd();
10023
+ this.heldSpace = body.slice(kept.length);
10024
+ if (!kept)
10025
+ return;
10026
+ if (this.blockStart) {
10027
+ this.blockStart = false;
10028
+ this.reasoning(this.gap() + kept);
10029
+ } else {
10030
+ this.reasoning(kept);
10031
+ }
10002
10032
  }
10003
10033
  tool(name, target) {
10004
10034
  if (this.closed || !name)
10005
10035
  return;
10006
10036
  this.drainText();
10007
10037
  this.reasoningTail = null;
10038
+ this.heldSpace = "";
10008
10039
  this.push({ kind: "tool", tool: target ? { name, target } : { name } });
10009
10040
  this.flush();
10010
10041
  }
@@ -10029,6 +10060,11 @@ var require_progress = __commonJS({
10029
10060
  this.closed = true;
10030
10061
  this.clearTimer();
10031
10062
  }
10063
+ /** The break that sets a new block off from the reasoning before it. */
10064
+ gap() {
10065
+ const tail = this.reasoningTail;
10066
+ return tail === null || tail.endsWith("\n\n") ? "" : tail.endsWith("\n") ? "\n" : "\n\n";
10067
+ }
10032
10068
  drainText() {
10033
10069
  if (this.textBuf.length === 0)
10034
10070
  return;
@@ -10058,6 +10094,8 @@ var require_progress = __commonJS({
10058
10094
  var StreamJsonTap = class {
10059
10095
  handlers;
10060
10096
  buf = "";
10097
+ /** The messages whose reasoning arrived as deltas, by API message id. */
10098
+ streamed = /* @__PURE__ */ new Set();
10061
10099
  constructor(handlers) {
10062
10100
  this.handlers = handlers;
10063
10101
  }
@@ -10087,12 +10125,18 @@ var require_progress = __commonJS({
10087
10125
  } catch {
10088
10126
  return;
10089
10127
  }
10090
- if (event.type === "assistant") {
10091
- const content = event.message?.content;
10128
+ if (event.type === "stream_event") {
10129
+ this.consumeStreamEvent(event.event);
10130
+ } else if (event.type === "assistant") {
10131
+ const message = event.message;
10132
+ const content = message?.content;
10092
10133
  if (!Array.isArray(content))
10093
10134
  return;
10135
+ const streamed = typeof message?.id === "string" && this.streamed.has(message.id);
10094
10136
  for (const block of content) {
10095
10137
  const b = block;
10138
+ if (streamed && b?.type !== "tool_use")
10139
+ continue;
10096
10140
  if (b?.type === "text" && typeof b.text === "string" && b.text.length > 0) {
10097
10141
  this.handlers.onReasoning?.(b.text);
10098
10142
  } else if (b?.type === "thinking" && typeof b.thinking === "string" && b.thinking.length > 0) {
@@ -10105,6 +10149,24 @@ var require_progress = __commonJS({
10105
10149
  this.handlers.onResult?.();
10106
10150
  }
10107
10151
  }
10152
+ consumeStreamEvent(event) {
10153
+ if (!event)
10154
+ return;
10155
+ if (event.type === "message_start") {
10156
+ const id = event.message?.id;
10157
+ if (typeof id === "string")
10158
+ this.streamed.add(id);
10159
+ } else if (event.type === "content_block_start") {
10160
+ const kind = event.content_block?.type;
10161
+ if (kind === "thinking" || kind === "text")
10162
+ this.handlers.onReasoningStart?.();
10163
+ } else if (event.type === "content_block_delta") {
10164
+ const delta = event.delta;
10165
+ const text = delta?.type === "thinking_delta" ? delta.thinking : delta?.type === "text_delta" ? delta.text : void 0;
10166
+ if (typeof text === "string" && text.length > 0)
10167
+ this.handlers.onReasoningDelta?.(text);
10168
+ }
10169
+ }
10108
10170
  };
10109
10171
  exports2.StreamJsonTap = StreamJsonTap;
10110
10172
  function toolTarget(input) {
@@ -11015,6 +11077,8 @@ var require_claude_code = __commonJS({
11015
11077
  const args = ["--print", "--output-format", "stream-json", "--verbose", ...reviewRunArgs(settingSources)];
11016
11078
  if (resumeSessionId)
11017
11079
  args.push("--resume", resumeSessionId);
11080
+ if (reporter)
11081
+ args.push("--include-partial-messages");
11018
11082
  if (spec.outputSchema && typeof spec.outputSchema === "object" && Object.keys(spec.outputSchema).length > 0) {
11019
11083
  args.push("--json-schema", JSON.stringify(spec.outputSchema));
11020
11084
  }
@@ -11033,6 +11097,8 @@ var require_claude_code = __commonJS({
11033
11097
  }
11034
11098
  const tap = reporter ? new progress_1.StreamJsonTap({
11035
11099
  onReasoning: (t) => reporter.reasoningBlock(t),
11100
+ onReasoningStart: () => reporter.beginBlock(),
11101
+ onReasoningDelta: (t) => reporter.reasoningDelta(t),
11036
11102
  onTool: (name, target) => reporter.tool(name, target),
11037
11103
  onResult: () => reporter.flush()
11038
11104
  }) : null;
@@ -12732,7 +12798,7 @@ var require_client = __commonJS({
12732
12798
  ttlSeconds: request.ttlSeconds
12733
12799
  });
12734
12800
  }
12735
- // ── Managed Sifter ──────────────────────────────────────────────
12801
+ // ── Hosted Sifter ───────────────────────────────────────────────
12736
12802
  /**
12737
12803
  * Reveal a person's model-provider key for one hosted dispatch, with the
12738
12804
  * provider it is for (ADR-0127). Service-token only; requires
@@ -12745,17 +12811,6 @@ var require_client = __commonJS({
12745
12811
  async revealModelCredential(userId, options = {}) {
12746
12812
  return this.request("POST", `/api/users/${encodeURIComponent(userId)}/model-credential`, options.provider ? { provider: options.provider } : {});
12747
12813
  }
12748
- /**
12749
- * Read a user's hosted-Sifter opt-in status. Returns `{enabled:
12750
- * false}` for users who never opted in (no row) and users who
12751
- * opted in then disabled. Service-to-service only; requires the
12752
- * `keep:managed-sifter-enrollments:read` scope, which is distinct
12753
- * from `keep:managed-sifter-key-material:read` so a service identity
12754
- * can hold one without the other.
12755
- */
12756
- async getManagedSifterStatus(userId) {
12757
- return this.request("GET", `/api/users/${encodeURIComponent(userId)}/managed-sifter-status`);
12758
- }
12759
12814
  // ── GitHub OAuth token ──────────────────────────────────────────
12760
12815
  /**
12761
12816
  * Reveal a user's decrypted GitHub OAuth token for a service-to-service
@@ -29414,7 +29469,7 @@ var import_path = require("path");
29414
29469
  var import_promises = require("fs/promises");
29415
29470
  var import_yaml = __toESM(require_dist3());
29416
29471
  var import_shuttle = __toESM(require_dist5());
29417
- var buildVersion = true ? "0.38.0" : pkg.version;
29472
+ var buildVersion = true ? "0.39.0" : pkg.version;
29418
29473
  var AGENT_EXECUTORS = ["claude-code", "codex", "copilot"];
29419
29474
  var sifterBrand = {
29420
29475
  product: {