@yanlinglabs/winter-agent-runtime 0.0.43 → 0.0.44

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.
@@ -133,6 +133,21 @@ export declare function announcedDeferredTools(messages: readonly ProviderMessag
133
133
  * re-announced if it defers again.
134
134
  */
135
135
  export declare function computeDeferredToolsDelta(deferred: readonly string[], offered: readonly string[], history: readonly ProviderMessage[]): DeferredToolsDeltaAttachment | undefined;
136
+ /**
137
+ * A host message folded into the RUNNING turn (the engine's `foldPendingHostInput`): the user sent it
138
+ * while the model was working, and it reaches the model right after the turn's last tool results
139
+ * instead of waiting for a turn of its own. Stored as claude's own `queued_command` entry for a typed
140
+ * prompt (`commandMode: "prompt"`, no `origin`), so a resumed session rebuilds the same history.
141
+ */
142
+ export interface QueuedPromptAttachment extends AttachmentPayload {
143
+ type: "queued_command";
144
+ prompt: string;
145
+ commandMode: "prompt";
146
+ }
147
+ /** The two fixed lines around a folded message (claude's interface text, unchanged). */
148
+ export declare const QUEUED_PROMPT_HEADER = "The user sent a new message while you were working:";
149
+ export declare const QUEUED_PROMPT_FOOTER = "IMPORTANT: After completing your current task, you MUST address the user's message above. Do not ignore it.";
150
+ export declare function queuedPromptAttachment(prompt: string): QueuedPromptAttachment;
136
151
  /** The wrapped model-facing text for an attachment, or `undefined` when there is none (an unknown type included). */
137
152
  export declare function renderAttachment(attachment: AttachmentPayload): string | undefined;
138
153
  /** The history message for an attachment, or `undefined` when it renders to nothing (it is then not appended at all). */
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  Queue
3
- } from "./index-97t2rmtf.js";
3
+ } from "./index-dne3dw18.js";
4
4
 
5
5
  // src/embedded-host.ts
6
6
  var EMBEDDED_KILL_GRACE_MS = 1500;
@@ -1,4 +1,4 @@
1
- import"./index-kqc3tdph.js";
1
+ import"./index-hbkdq3xs.js";
2
2
  import {
3
3
  liveProcessGroups,
4
4
  onProcessGroupChange
@@ -6,13 +6,13 @@ import {
6
6
  import"./index-mwew595z.js";
7
7
  import"./index-2wgfv0pa.js";
8
8
  import"./index-bef62z3r.js";
9
- import"./index-bh1ve8ws.js";
9
+ import"./index-r1pter2v.js";
10
10
  import {
11
11
  runEmbeddedSession2
12
- } from "./index-14xkt4jp.js";
12
+ } from "./index-x7hdare6.js";
13
13
  import {
14
14
  Queue
15
- } from "./index-97t2rmtf.js";
15
+ } from "./index-dne3dw18.js";
16
16
 
17
17
  // src/embedded-worker.ts
18
18
  import { isMainThread } from "node:worker_threads";
package/dist/embedded.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  runEmbeddedSession2
3
- } from "./index-14xkt4jp.js";
4
- import"./index-bh1ve8ws.js";
5
- import"./index-kqc3tdph.js";
3
+ } from "./index-x7hdare6.js";
4
+ import"./index-r1pter2v.js";
5
+ import"./index-hbkdq3xs.js";
6
6
  import"./index-2wgfv0pa.js";
7
7
  import"./index-bef62z3r.js";
8
8
  import"./index-1hef2gff.js";
@@ -15,6 +15,17 @@ class Queue {
15
15
  for (const r of this.resolvers.splice(0))
16
16
  r({ value: undefined, done: true });
17
17
  }
18
+ pending() {
19
+ return [...this.buf];
20
+ }
21
+ remove(values) {
22
+ const before = this.buf.length;
23
+ this.buf = this.buf.filter((v) => !values.has(v));
24
+ return before - this.buf.length;
25
+ }
26
+ restore(values) {
27
+ this.buf.unshift(...values);
28
+ }
18
29
  async* [Symbol.asyncIterator]() {
19
30
  while (true) {
20
31
  if (this.buf.length) {
@@ -26,7 +26,7 @@ import {
26
26
  } from "./index-2wgfv0pa.js";
27
27
  import {
28
28
  Queue
29
- } from "./index-97t2rmtf.js";
29
+ } from "./index-dne3dw18.js";
30
30
 
31
31
  // src/rpc/bridge.ts
32
32
  import { randomUUID } from "node:crypto";
@@ -2753,6 +2753,20 @@ registerAttachmentRenderer("tool_changes", (a) => {
2753
2753
  const parts = [...names("add").map((n) => `+${n}`), ...names("remove").map((n) => `-${n}`)];
2754
2754
  return `[tools changed: ${parts.length > 0 ? parts.join(" ") : "declarations only"}]`;
2755
2755
  }, { wrap: false });
2756
+ var QUEUED_PROMPT_HEADER = "The user sent a new message while you were working:";
2757
+ var QUEUED_PROMPT_FOOTER = "IMPORTANT: After completing your current task, you MUST address the user's message above. Do not ignore it.";
2758
+ function queuedPromptAttachment(prompt) {
2759
+ return { type: "queued_command", prompt, commandMode: "prompt" };
2760
+ }
2761
+ registerAttachmentRenderer("queued_command", (a) => {
2762
+ const prompt = a["prompt"];
2763
+ if (a["commandMode"] !== "prompt" || a["origin"] !== undefined || typeof prompt !== "string")
2764
+ return;
2765
+ return `${QUEUED_PROMPT_HEADER}
2766
+ ${neutralizeReminderTags(prompt)}
2767
+
2768
+ ${QUEUED_PROMPT_FOOTER}`;
2769
+ });
2756
2770
  function renderAttachment(attachment) {
2757
2771
  const renderer = renderers.get(attachment.type);
2758
2772
  if (renderer === undefined)
@@ -25992,6 +26006,88 @@ ${escapeAttributionText(msg.body)}
25992
26006
  output.write({ type: "data", ...buildSdkInitMessage() });
25993
26007
  };
25994
26008
  const userFrames = new Queue;
26009
+ const hostInputFrames = new WeakSet;
26010
+ const endsFold = async (text) => {
26011
+ if (resolveBuiltinCommand(text) !== undefined)
26012
+ return true;
26013
+ if (!looksLikeCommand(text) || commandResolver === undefined)
26014
+ return false;
26015
+ try {
26016
+ return (await commandResolver.resolve(text, config.cwd)).kind !== "none";
26017
+ } catch {
26018
+ return true;
26019
+ }
26020
+ };
26021
+ const recordFoldedInput = async (attachment) => {
26022
+ if (store?.recordAttachmentEntry === undefined)
26023
+ return true;
26024
+ try {
26025
+ await store.recordAttachmentEntry(attachment);
26026
+ return true;
26027
+ } catch {
26028
+ return false;
26029
+ }
26030
+ };
26031
+ const foldPendingHostInput = async (signal) => {
26032
+ const accepted = [];
26033
+ for (const frame of userFrames.pending()) {
26034
+ if (signal.aborted)
26035
+ return;
26036
+ if (!hostInputFrames.has(frame))
26037
+ continue;
26038
+ if (await endsFold(frame.text))
26039
+ break;
26040
+ let composite;
26041
+ try {
26042
+ composite = await fireObservationalHook("UserPromptSubmit", { payload: { prompt: frame.text } });
26043
+ } catch {
26044
+ break;
26045
+ }
26046
+ if (contextStrings(composite.blockReasons).length > 0 || composite.preventContinuation !== undefined)
26047
+ break;
26048
+ accepted.push({ frame, composite });
26049
+ }
26050
+ if (accepted.length === 0 || signal.aborted)
26051
+ return;
26052
+ const stillPending = new Set(userFrames.pending());
26053
+ const claimed = [];
26054
+ for (const entry of accepted) {
26055
+ if (!stillPending.has(entry.frame))
26056
+ break;
26057
+ claimed.push(entry);
26058
+ }
26059
+ if (claimed.length === 0)
26060
+ return;
26061
+ userFrames.remove(new Set(claimed.map((c) => c.frame)));
26062
+ let folded = 0;
26063
+ for (const [index, { frame, composite }] of claimed.entries()) {
26064
+ const attachment = queuedPromptAttachment(frame.text);
26065
+ if (!await recordFoldedInput(attachment)) {
26066
+ userFrames.restore(claimed.slice(index).map((c) => c.frame));
26067
+ break;
26068
+ }
26069
+ const message = attachmentMessage(attachment);
26070
+ if (message !== undefined)
26071
+ messages.push(message);
26072
+ for (const notice of contextStrings(composite.systemMessages))
26073
+ emitHookNotice(notice);
26074
+ const context = hookAdditionalContextAttachment("UserPromptSubmit", contextStrings(composite.extraContext));
26075
+ if (context !== undefined) {
26076
+ const contextMessage = attachmentMessage(context);
26077
+ if (contextMessage !== undefined) {
26078
+ messages.push(contextMessage);
26079
+ await recordAttachment(context);
26080
+ }
26081
+ }
26082
+ folded++;
26083
+ }
26084
+ if (folded === 0)
26085
+ return;
26086
+ try {
26087
+ output.write({ type: "data", message: { type: "system", subtype: "host_input_folded", count: folded, uuid: randomUUID18(), session_id: config.sessionId } });
26088
+ } catch {}
26089
+ };
26090
+ const clearPendingHostInputs = () => userFrames.remove(new Set(userFrames.pending().filter((frame) => hostInputFrames.has(frame))));
25995
26091
  const notifications = notificationQueueFor(config.sessionId);
25996
26092
  let turnActive = false;
25997
26093
  let controlCompaction;
@@ -26175,6 +26271,7 @@ ${escapeAttributionText(msg.body)}
26175
26271
  return;
26176
26272
  const frame = outcome.result.value;
26177
26273
  if (frame.type === "user") {
26274
+ hostInputFrames.add(frame);
26178
26275
  userFrames.write(frame);
26179
26276
  continue;
26180
26277
  }
@@ -26289,6 +26386,10 @@ ${escapeAttributionText(msg.body)}
26289
26386
  });
26290
26387
  continue;
26291
26388
  }
26389
+ if (cf.subtype === "clear_queued_input") {
26390
+ output.write({ type: "control_response", requestId: cf.requestId, ok: true, payload: { cleared: clearPendingHostInputs() } });
26391
+ continue;
26392
+ }
26292
26393
  if (cf.subtype === "list_models") {
26293
26394
  output.write({ type: "control_response", requestId: cf.requestId, ok: true, payload: supportedModels?.() ?? [] });
26294
26395
  continue;
@@ -27700,6 +27801,7 @@ ${reason}` : ""}` : `${promptStop.hookName} hook stopped continuation${reason.le
27700
27801
  terminal_reason: "prompt_too_long",
27701
27802
  api_error_status: status
27702
27803
  });
27804
+ let toolRoundEnded = false;
27703
27805
  roundLoop:
27704
27806
  while (true) {
27705
27807
  if (interruptedAwaitingMcp) {
@@ -27724,6 +27826,8 @@ ${reason}` : ""}` : `${promptStop.hookName} hook stopped continuation${reason.le
27724
27826
  finalResult = takeHookStopResult();
27725
27827
  break roundLoop;
27726
27828
  }
27829
+ const foldAfterToolRound = toolRoundEnded;
27830
+ toolRoundEnded = false;
27727
27831
  let turn;
27728
27832
  let sentPerMessageBeta = false;
27729
27833
  let sentToolChanges = false;
@@ -27734,6 +27838,8 @@ ${reason}` : ""}` : `${promptStop.hookName} hook stopped continuation${reason.le
27734
27838
  try {
27735
27839
  const context = await ensureSessionContext(assembled, envelopeInput);
27736
27840
  const effortPlan = planEffort();
27841
+ if (foldAfterToolRound && config.agentId === undefined)
27842
+ await foldPendingHostInput(turnAbort.signal);
27737
27843
  const toolPlan = await planToolsForRequest();
27738
27844
  const toolSpecs = toolPlan.tools;
27739
27845
  sentToolChanges = toolPlan.optIn === true || (toolPlan.toolChanges?.render.size ?? 0) > 0;
@@ -28429,6 +28535,7 @@ ${reason}` : ""}` : `${promptStop.hookName} hook stopped continuation${reason.le
28429
28535
  break roundLoop;
28430
28536
  }
28431
28537
  await scanAttachments("tool-round");
28538
+ toolRoundEnded = true;
28432
28539
  }
28433
28540
  if (!stopHookFired)
28434
28541
  await fireStopHooks(undefined);
@@ -29665,7 +29772,7 @@ class TranscriptWriter2 {
29665
29772
  return entries;
29666
29773
  }
29667
29774
  }
29668
- var RUNTIME_ENGINE_VERSION2 = "0.0.43";
29775
+ var RUNTIME_ENGINE_VERSION2 = "0.0.44";
29669
29776
  function withPermissionJournal(writer, location) {
29670
29777
  return {
29671
29778
  transcriptPath: join27(location.winterHome, "projects", location.projectKey, `${location.sessionId}.jsonl`),
@@ -85,7 +85,7 @@ import {
85
85
  providerCredentialRef2,
86
86
  createModelClassifier2,
87
87
  selectClassifierRoute2
88
- } from "./index-kqc3tdph.js";
88
+ } from "./index-hbkdq3xs.js";
89
89
  import {
90
90
  createKeychainCredentialStore,
91
91
  createKeychainSecretReader,
@@ -98,7 +98,7 @@ import {
98
98
  } from "./index-mwew595z.js";
99
99
  import {
100
100
  createInMemoryChannel2
101
- } from "./index-97t2rmtf.js";
101
+ } from "./index-dne3dw18.js";
102
102
 
103
103
  // src/subagents/child-engine.ts
104
104
  import { randomUUID } from "node:crypto";
@@ -9,14 +9,14 @@ import {
9
9
  resolveEngineSession2,
10
10
  resolveProductionWinterHome2,
11
11
  resolveProductionStoreHome
12
- } from "./index-kqc3tdph.js";
12
+ } from "./index-hbkdq3xs.js";
13
13
  import {
14
14
  registerDefaultChildEngineFactory,
15
15
  loadResumedChain,
16
16
  buildProductionWiring,
17
17
  withAutoSkillPermissions,
18
18
  restoreChildRoster
19
- } from "./index-bh1ve8ws.js";
19
+ } from "./index-r1pter2v.js";
20
20
 
21
21
  // src/embedded.ts
22
22
  import { splitFrames, encodeFrame } from "@yanlinglabs/winter-agent-sdk";
package/dist/index.js CHANGED
@@ -55,14 +55,14 @@ import {
55
55
  DEFAULT_CLASSIFIER_TIMEOUT_MS2,
56
56
  createModelClassifier2,
57
57
  selectClassifierRoute2
58
- } from "./index-kqc3tdph.js";
58
+ } from "./index-hbkdq3xs.js";
59
59
  import"./index-1hef2gff.js";
60
60
  import"./index-mwew595z.js";
61
61
  import"./index-2wgfv0pa.js";
62
62
  import"./index-bef62z3r.js";
63
63
  import {
64
64
  createInMemoryChannel2
65
- } from "./index-97t2rmtf.js";
65
+ } from "./index-dne3dw18.js";
66
66
 
67
67
  // src/runtime.ts
68
68
  async function runWinterRuntime(opts) {
@@ -14,6 +14,12 @@ export declare class Queue<T> implements AsyncIterable<T> {
14
14
  private ended;
15
15
  write(v: T): void;
16
16
  end(): void;
17
+ /** The values written but not yet read, oldest first. A copy: changing it changes nothing here. */
18
+ pending(): T[];
19
+ /** Drops these values if they are still waiting to be read (one already read is untouched); answers how many were dropped. */
20
+ remove(values: ReadonlySet<T>): number;
21
+ /** Puts values taken with `remove` back at the HEAD, in order (they were the oldest). For a reader that is mid-item, never one waiting on `write`. */
22
+ restore(values: readonly T[]): void;
17
23
  [Symbol.asyncIterator](): AsyncGenerator<Awaited<T>, void, unknown>;
18
24
  }
19
25
  export declare function createInMemoryChannel(): {
@@ -478,7 +478,7 @@ export declare class TranscriptWriter implements SessionPersistence {
478
478
  private dialectRecord;
479
479
  static readBack(store: SessionStore, key: SessionKey): Promise<SessionStoreEntry[]>;
480
480
  }
481
- export declare const RUNTIME_ENGINE_VERSION = "0.0.43";
481
+ export declare const RUNTIME_ENGINE_VERSION = "0.0.44";
482
482
  export interface ResolvedEngineSession {
483
483
  config: RuntimeConfig;
484
484
  store: SessionPersistence | undefined;
package/dist/testing.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  runEngine2,
4
4
  echoProvider2,
5
5
  resolveEngineSession2
6
- } from "./index-kqc3tdph.js";
6
+ } from "./index-hbkdq3xs.js";
7
7
  import"./index-1hef2gff.js";
8
8
  import"./index-mwew595z.js";
9
9
  import"./index-2wgfv0pa.js";
@@ -14,10 +14,10 @@ import {
14
14
  buildProductionWiring,
15
15
  withAutoSkillPermissions,
16
16
  restoreChildRoster
17
- } from "./index-bh1ve8ws.js";
17
+ } from "./index-r1pter2v.js";
18
18
  import {
19
19
  Queue
20
- } from "./index-97t2rmtf.js";
20
+ } from "./index-dne3dw18.js";
21
21
 
22
22
  // src/testing.ts
23
23
  import { mkdtempSync } from "node:fs";
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const RUNTIME_VERSION = "0.0.43";
1
+ export declare const RUNTIME_VERSION = "0.0.44";
package/dist/version.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/version.ts
2
- var RUNTIME_VERSION = "0.0.43";
2
+ var RUNTIME_VERSION = "0.0.44";
3
3
  export {
4
4
  RUNTIME_VERSION
5
5
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yanlinglabs/winter-agent-runtime",
3
- "version": "0.0.43",
3
+ "version": "0.0.44",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "engines": {
@@ -73,9 +73,9 @@
73
73
  "@modelcontextprotocol/client": "^2.1.0",
74
74
  "ajv": "^8.20.0",
75
75
  "ignore": "7.0.5",
76
- "@yanlinglabs/winter-agent-sdk": "0.0.43",
77
- "@yanlinglabs/winter-provider-runtime": "0.0.43",
78
- "@yanlinglabs/winter-provider-catalog": "0.0.43"
76
+ "@yanlinglabs/winter-agent-sdk": "0.0.44",
77
+ "@yanlinglabs/winter-provider-catalog": "0.0.44",
78
+ "@yanlinglabs/winter-provider-runtime": "0.0.44"
79
79
  },
80
80
  "devDependencies": {
81
81
  "@modelcontextprotocol/server": "^2.1.0"