@skaile/workspaces 4.28.2 → 4.29.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 4.29.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#925](https://github.com/skaile-ai/workspaces/pull/925) [`5579aeb`](https://github.com/skaile-ai/workspaces/commit/5579aeb0db740725b6651b6ebc17fcb63288f655) Thanks [@peteralbert](https://github.com/peteralbert)! - The runner now sends `status: idle` at the end of a turn only when no other prompt, reply or flow turn is queued behind it. Before, every turn end reported idle, so a host that clears per-turn state on idle (the platform's turn-principal ledger) lost the starters of the turns still queued, and those turns read as `unknown`. An idle held back this way is sent once the queue drains, even when the driver ends several queued prompts with one `agent_end` or the last turn fails. The compaction-end idle is unchanged.
8
+
3
9
  ## 4.28.2
4
10
 
5
11
  ### Patch Changes
@@ -4,7 +4,7 @@ import { findAiAssetsRoot } from './chunk-7IH3RKKK.js';
4
4
  import { WebSocketServerTransport } from './chunk-5LKOAX7I.js';
5
5
  import { assembleSystemPrompt, buildCapabilitiesPromptSection } from './chunk-W3UDISS2.js';
6
6
  import { prepareNativePolicy, codexInstanceEnvironment, parseCodexCredential, parseCodexRefreshInput, parseCodexRefreshResult } from './chunk-PE3A6FFW.js';
7
- import { resolveFlowPath } from './chunk-YU2CVP3M.js';
7
+ import { resolveFlowPath } from './chunk-G6NTA3BZ.js';
8
8
  import { findAiAssetsRoot as findAiAssetsRoot$1, deployCatalogEntry, undeployCatalogEntry } from './chunk-Q6NDQ6BH.js';
9
9
  import { registerBuiltinConnectors, buildConnectorPromptSection, findMissingPackages, installNpmPackages, ConnectorManager, buildSdkConnectorTools, buildLazySdkFlowTools, describeFlowOperations, buildConnectorToolDefs, buildFlowToolDefs, SessionNodeExecutor, SessionSubpromptRunner, ClassifierSubpromptRunner, SessionInlineSubFlowRunner, driveOrchestratorTurn, buildSdkFlowTools } from './chunk-FUKJ4IU6.js';
10
10
  import { loadYamlConnectorDeclarations, withMaterializedConnectorDeclarations, SecretProviderChain, ConnectorStartupError, PreMintedSecretProvider, InMemorySecretProvider, resolvedConfigToDeclarations, isKnownSecretRef, deriveSingleMaterializedConnectorDeclaration } from './chunk-2JANXYTJ.js';
@@ -4800,6 +4800,43 @@ var DriverSwapGate = class {
4800
4800
  }
4801
4801
  };
4802
4802
 
4803
+ // runner/src/pending-turns.ts
4804
+ var PendingTurns = class {
4805
+ constructor(emitIdle) {
4806
+ this.emitIdle = emitIdle;
4807
+ }
4808
+ emitIdle;
4809
+ count = 0;
4810
+ idleOwed = false;
4811
+ /** Count a turn as taken on. Returns an idempotent `end`; call it in a `finally`. */
4812
+ begin() {
4813
+ this.count += 1;
4814
+ let ended = false;
4815
+ return () => {
4816
+ if (ended) return;
4817
+ ended = true;
4818
+ this.count -= 1;
4819
+ if (this.count === 0 && this.idleOwed) {
4820
+ this.idleOwed = false;
4821
+ this.emitIdle();
4822
+ }
4823
+ };
4824
+ }
4825
+ /** Call at a turn's end, while that turn is still counted: whether to report idle now. */
4826
+ shouldReportIdle() {
4827
+ if (this.count > 1) {
4828
+ this.idleOwed = true;
4829
+ return false;
4830
+ }
4831
+ this.idleOwed = false;
4832
+ return true;
4833
+ }
4834
+ /** Turns taken on and not finished; for diagnostics and tests. */
4835
+ get size() {
4836
+ return this.count;
4837
+ }
4838
+ };
4839
+
4803
4840
  // runner/src/serial-lock.ts
4804
4841
  function createSerialLock() {
4805
4842
  let tail = Promise.resolve();
@@ -8822,6 +8859,9 @@ async function startAgentServer(opts) {
8822
8859
  let driverStartInFlight = null;
8823
8860
  const driverSwapGate = new DriverSwapGate();
8824
8861
  const compactionGate = new CompactionGate();
8862
+ const pendingTurns = new PendingTurns(() => {
8863
+ if (!compacting) sendEvent({ type: "status", phase: "idle" });
8864
+ });
8825
8865
  let driverRestartChain = Promise.resolve();
8826
8866
  let driver = secretsMode === "env" ? agentSession.driver : void 0;
8827
8867
  let secretsProvisioned = secretsMode === "env";
@@ -8932,7 +8972,13 @@ async function startAgentServer(opts) {
8932
8972
  if (driver !== starting) return;
8933
8973
  starting.on("agent-event", (event) => {
8934
8974
  const normalized = normalizer.normalize(event);
8935
- for (const e of normalized) forwardNormalizedEvent(e);
8975
+ const turnEnded = event.type === "agent_end";
8976
+ for (const e of normalized) {
8977
+ if (turnEnded && !compacting && e.type === "status" && e.phase === "idle" && !pendingTurns.shouldReportIdle()) {
8978
+ continue;
8979
+ }
8980
+ forwardNormalizedEvent(e);
8981
+ }
8936
8982
  });
8937
8983
  starting.on("error", (err) => {
8938
8984
  log(`[serve] driver error: ${err.message}`);
@@ -8984,18 +9030,28 @@ async function startAgentServer(opts) {
8984
9030
  return stimulusBus;
8985
9031
  }
8986
9032
  function awaitFlowAgentEnd(prompt, timeoutMs) {
8987
- return dispatchFlowTurn(
8988
- {
8989
- gate: driverSwapGate,
8990
- awaitCompactionIdle: () => awaitCompactionIdle("flow turn"),
8991
- isCompacting: () => !compactionGate.isIdle(),
8992
- ensureDriverStarted,
8993
- getDriver: () => driver
8994
- },
8995
- prompt,
8996
- timeoutMs
9033
+ return countPendingTurn(
9034
+ () => dispatchFlowTurn(
9035
+ {
9036
+ gate: driverSwapGate,
9037
+ awaitCompactionIdle: () => awaitCompactionIdle("flow turn"),
9038
+ isCompacting: () => !compactionGate.isIdle(),
9039
+ ensureDriverStarted,
9040
+ getDriver: () => driver
9041
+ },
9042
+ prompt,
9043
+ timeoutMs
9044
+ )
8997
9045
  );
8998
9046
  }
9047
+ async function countPendingTurn(run) {
9048
+ const end = pendingTurns.begin();
9049
+ try {
9050
+ return await run();
9051
+ } finally {
9052
+ end();
9053
+ }
9054
+ }
8999
9055
  function ensureResourceManagerForFlow() {
9000
9056
  if (!resourceManager) {
9001
9057
  registerBuiltinConnectors();
@@ -10041,7 +10097,7 @@ async function startAgentServer(opts) {
10041
10097
  log(`[serve] flow user-message turn failed: ${errMsg}`);
10042
10098
  sendEvent({ type: "error", message: `Flow turn failed: ${errMsg}`, fatal: false });
10043
10099
  } finally {
10044
- sendEvent({ type: "status", phase: "idle" });
10100
+ if (pendingTurns.shouldReportIdle()) sendEvent({ type: "status", phase: "idle" });
10045
10101
  }
10046
10102
  return;
10047
10103
  }
@@ -10366,10 +10422,10 @@ async function startAgentServer(opts) {
10366
10422
  await handleSessionInit(cmd);
10367
10423
  break;
10368
10424
  case "prompt":
10369
- await handlePrompt(cmd);
10425
+ await countPendingTurn(() => handlePrompt(cmd));
10370
10426
  break;
10371
10427
  case "reply":
10372
- await handleReply(cmd);
10428
+ await countPendingTurn(() => handleReply(cmd));
10373
10429
  break;
10374
10430
  case "cancel":
10375
10431
  await handleCancel();
@@ -10679,5 +10735,5 @@ function touchSession(state) {
10679
10735
  }
10680
10736
 
10681
10737
  export { CLAUDE_CODE_CREDENTIALS_KEY, COMPILE_MANIFEST_FILENAME, CapabilityRegistry, DEFAULT_CAPABILITY_CALL_TIMEOUT_MS, DEFAULT_COALESCE_MS, DEFAULT_FLOW_MUTATE_CONNECTOR_WAIT_MS, MOUNT_LIST_MAX_DEPTH, MOUNT_LIST_MAX_ENTRIES, MOUNT_READ_DEADLINE_FACTOR, MOUNT_STAT_BUDGET_MS, MOUNT_STAT_MAX_ENTRIES, MOUNT_TREE_OP_DEADLINE_FACTOR, MarkdownStreamer, PreInitRingSink, ResourceOperationError, SESSION_ROOT_WRITABLE_DIRS, SESSION_ROOT_WRITABLE_FILES, WS_AUTH_TOKEN_ENV, WS_AUTH_TOKEN_FILE_ENV, agentDefinitionExists, bootstrapCapabilityRegistry, bootstrapRunnerLogStore, buildAgentResources, buildClientCapabilityHandler, buildConnectorTokenMediator, buildContextSection, buildEnvironmentSection, buildResourcesAvailablePayload, buildStoreSnapshotReplay, builtinCapabilities, capabilityLogInstance, clearPreInitRingSink, clearSession, compileComposition, computeCapabilitySignature, computeDirectoryTotals, connectorRefreshKind, createAgentSession, createFlowConnectorReadiness, createManagedCodexSubpromptDriver, createSessionStimulusBus, defineCapability, deleteSession, dispatchResourceRequest, dispatchRunnerCapabilityInvocation, emitSystemPromptComposed, ensureClaudeSettingsDisablesConnectors, ensureGitConfigInclude, executeConnectorMutate, extractClaudeAiOauthExpiresAt, flowRunDrivesTurns, flowStartNeedsDriverRestart, getPreInitRingSink, handleMountResourceRequest, handleResourceRequest, handleSessionRootResourceRequest, hasNonTerminalFlow, hostOpResumeStimulus, installPreInitRingSink, isSessionRootPathAllowed, isTerminalFlowStatus, listSessions, loadAgentManifest, loadCompileManifest, loadCompileManifestFromDir, loadManagedCodexHostConfig, loadSession, loadSessionById, mcpAuthSecretKey, newSession, nulTailPaddingLength, pickChatFlowTarget, pickFlowToolTarget, pickRepointedManager, planFlowMutate, prepareCodexTools, reconcilePendingDecisions, recreateKeepingLiveFlows, registerActiveFlow, registerCompositionCapabilities, rejectCapabilityOnApprovalDeny, rejectPendingCapabilityCallsOnDisconnect, resetRunnerLogStore, resolveAgentComposition, resolveAgentMixins, resolveBinding, resolveCapabilityCallTimeoutMs, resolveCapabilityResult, resolveComposition, resolveFlowMutateConnectorWaitMs, resolveMixin, restoredRunHasWorkToResume, runAgentChat, saveSession, setCurrentSession, setUpFlowConnector, startAgentServer, stimulusFromMetas, supportsLiveToolUpdates, takeRunnerWsAuthToken, toActiveFlowTarget, touchSession, validateInputResponse, writeClaudeCodeCredentialsFile };
10682
- //# sourceMappingURL=chunk-RPZ6ZE7S.js.map
10683
- //# sourceMappingURL=chunk-RPZ6ZE7S.js.map
10738
+ //# sourceMappingURL=chunk-3XMGAODZ.js.map
10739
+ //# sourceMappingURL=chunk-3XMGAODZ.js.map