@standardagents/builder 0.29.1 → 0.29.2

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.
@@ -396,7 +396,10 @@ interface ThreadInstance {
396
396
  getValue<T = unknown>(key: string): Promise<T | null>;
397
397
  setValue(key: string, value: unknown): Promise<void>;
398
398
  emitThreadEvent?(threadId: string, event: string, data: unknown): void | Promise<void>;
399
- callClientTool?(request: ClientToolRequest): Promise<ClientToolResponse>;
399
+ callClientTool?(request: ClientToolRequest, durability?: {
400
+ toolCallId: string;
401
+ side: "a" | "b";
402
+ }): Promise<ClientToolResponse>;
400
403
  openClientStream?(request: ClientStreamRequest): Promise<ClientStreamResponse>;
401
404
  dispatchClientTool?(request: ClientToolRequest, toolCallId: string, side: "a" | "b"): Promise<{
402
405
  dispatched: boolean;
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { ModelDefinition, AgentDefinition } from './runtime.js';
2
2
  export { AgentBuilderEnv, AuthContext, AuthUser, BroadcastOptions, CodeExecutionBridge, DurableAgentBuilder, DurableThread, DurableUserHub, FlowStateSdk, FlowStateWithSdk, HubClientInfo, ImageContextConfig, InjectMessageOptions, LLMProviderInterface, NamespaceResolutionError, PromptContent, PromptDefinition, PromptIncludePart, PromptPart, PromptToolConfig, Provider, ProviderContentPart, ProviderFilePart, ProviderImagePart, ProviderRegistry, ProviderTextPart, SessionToolBinding, SessionToolConfig, SideConfig, SubagentToolConfig, SubpromptConfig, ThreadRegistryEntry, ThreadWatchdog, ThreadWatchdogState, ToolConfig, UpdateThreadParams, User, WatchdogCheckin, WatchdogProbeResult, authenticate, buildImageDescription, cat, createNamespaceContext, emitThreadEvent, enhanceFlowState, exists, find, forceTurn, generateImageDescription, getFileStats, getMessages, getMessagesToSummarize, getShortName, getThumbnail, getUnsummarizedImageAttachments, getVisibleAgentNames, getVisibleModelNames, getVisiblePromptNames, getVisibleToolNames, grep, hasImageAttachments, head, injectMessage, isQualifiedName, linkFile, mkdir, move, optimizeImageContext, parseQualifiedName, qualifyName, queueTool, readFile, readdir, reloadHistory, rename, replaceImagesWithDescriptions, requireAdmin, requireAuth, resolveAgent, resolveHook, resolveModel, resolvePrompt, resolveTool, rmdir, stat, tail, unlink, updateThread, writeFile, writeImage } from './runtime.js';
3
3
  export { AgentPluginOptions, agentbuilder, builder } from './plugin.js';
4
- export { A as Agent, x as AttachmentRef, f as BuilderThreadEndpointHandler, C as CLIENT_STREAM_CHUNK_BYTES, o as ClientDuplex, p as ClientForwarding, m as ClientStreamRequest, n as ClientStreamResponse, k as ClientToolRequest, l as ClientToolResponse, B as Controller, a as ControllerContext, E as Env, w as FileRecord, y as FileStats, u as FlowResult, F as FlowState, G as GrepResult, D as ImageContentPart, I as ImageMetadata, L as LLMResponse, M as Message, J as MessageContent, H as MultimodalContent, R as RequestContext, S as StorageBackend, v as TelemetryEvent, z as TextContentPart, b as ThreadEndpointContext, e as ThreadEnv, q as ThreadInstance, r as ThreadMetadata, T as ToolCall, t as ToolResult, g as callClient, h as callClientStream, c as createThreadEndpointHandler, j as decodeStreamChunk, d as defineController, i as encodeStreamChunk, s as supportsClientForwarding } from './index-BNLDsLsL.js';
4
+ export { A as Agent, x as AttachmentRef, f as BuilderThreadEndpointHandler, C as CLIENT_STREAM_CHUNK_BYTES, o as ClientDuplex, p as ClientForwarding, m as ClientStreamRequest, n as ClientStreamResponse, k as ClientToolRequest, l as ClientToolResponse, B as Controller, a as ControllerContext, E as Env, w as FileRecord, y as FileStats, u as FlowResult, F as FlowState, G as GrepResult, D as ImageContentPart, I as ImageMetadata, L as LLMResponse, M as Message, J as MessageContent, H as MultimodalContent, R as RequestContext, S as StorageBackend, v as TelemetryEvent, z as TextContentPart, b as ThreadEndpointContext, e as ThreadEnv, q as ThreadInstance, r as ThreadMetadata, T as ToolCall, t as ToolResult, g as callClient, h as callClientStream, c as createThreadEndpointHandler, j as decodeStreamChunk, d as defineController, i as encodeStreamChunk, s as supportsClientForwarding } from './index-CcnGEkPh.js';
5
5
  export { AgentType, DefinitionLoader, GlobalNamespaceContext, HookSignatures, ImageContent, ModelCapabilities, ModelProvider, NamespaceContext, PackageSignature, PackedExports, PackedMeta, PackedMetadata, PackedNamespaceContext, PromptInput, PromptTextPart, ProviderAssistantMessage, ProviderConfigSlot, ProviderConfigSlots, ProviderConfigValueSource, ProviderDefinition, ProviderError, ProviderErrorCode, ProviderFactory, ProviderFactoryConfig, ProviderFinishReason, ProviderGeneratedImage, ProviderMessage, ProviderMessageContent, ProviderMethodOverrides, ModelCapabilities as ProviderModelCapabilities, ProviderOverride, ProviderOverrideContext, ProviderReasoningDetail, ProviderRequest, ProviderResponse, ProviderStreamChunk, ProviderSyncOverride, ProviderSystemMessage, ProviderTool, ProviderToolCallPart, ProviderToolMessage, ProviderToolResultContent, ProviderUsage, ProviderUserMessage, ReasoningConfig, StructuredPrompt, TextContent, Tool, ToolArgs, ToolArgsNode, ToolArgsRawShape, ToolContent, belongsToPackage, defineAgent, defineHook, defineModel, definePrompt, defineProvider, defineTool, isPacked, isVisibleInNamespace, mapReasoningLevel, providerConst, providerEnv, providerValue } from '@standardagents/spec';
6
6
  export { C as ConstituentItem, D as DiscoveredPackage, N as NamespacedRegistry, P as PackingAnalysis, a as PackingOptions, b as PackingResult, c as UnpackOptions, d as UnpackResult } from './types-Bpe7IANZ.js';
7
7
  export { D as DiscoveryConfig, P as PackageDiscoveryService, d as discoverPackages } from './discovery-DiMJWisl.js';
package/dist/index.js CHANGED
@@ -13545,7 +13545,10 @@ var init_ThreadStateImpl = __esm({
13545
13545
  data: { deferred: true, toolCallId }
13546
13546
  };
13547
13547
  }
13548
- const local = await this._threadInstance.callClientTool(request);
13548
+ const local = await this._threadInstance.callClientTool(
13549
+ request,
13550
+ canPark && toolCallId ? { toolCallId, side } : void 0
13551
+ );
13549
13552
  if (local.ok || !this.isNoClient(local)) return local;
13550
13553
  const env = this._threadInstance.env;
13551
13554
  if (env?.AGENT_BUILDER_THREAD) {
@@ -28279,7 +28282,7 @@ ${resultContent}${attachmentSummary}`;
28279
28282
  }
28280
28283
  /** Whether any forwarded call is mid-flight (blocking await or parked). */
28281
28284
  async hasInFlightClientCalls() {
28282
- if (this.pendingClientCalls.size > 0) return true;
28285
+ if ((this.pendingClientCalls?.size ?? 0) > 0) return true;
28283
28286
  await this.ensureMigrated();
28284
28287
  await this.ensurePendingClientTable();
28285
28288
  const cursor = await this.ctx.storage.sql.exec(
@@ -28338,7 +28341,7 @@ ${resultContent}${attachmentSummary}`;
28338
28341
  * always produce a normal tool error (no client connected, timeout, or user
28339
28342
  * denial) for the model to reason about.
28340
28343
  */
28341
- async callClientTool(request) {
28344
+ async callClientTool(request, durability) {
28342
28345
  const owner = await this.getExecutionOwner();
28343
28346
  const socket = this.getOpenBridgeSocket(owner?.client_id ?? null);
28344
28347
  if (!socket) {
@@ -28348,7 +28351,33 @@ ${resultContent}${attachmentSummary}`;
28348
28351
  data: { noClient: true }
28349
28352
  };
28350
28353
  }
28351
- const id = crypto.randomUUID();
28354
+ if (durability) {
28355
+ try {
28356
+ await this.ensureMigrated();
28357
+ await this.ensurePendingClientTable();
28358
+ const ownerId = owner?.client_id ?? null;
28359
+ const socketClientId = this.bridgeClientInfo.get(socket)?.clientId ?? null;
28360
+ const fenced = owner && socketClientId === owner.client_id;
28361
+ await this.ctx.storage.sql.exec(
28362
+ `INSERT OR REPLACE INTO pending_client_calls
28363
+ (tool_call_id, tool, args, request_permission, risk, side, status, created_at,
28364
+ dispatched_client_id, dispatched_generation)
28365
+ VALUES (?, ?, ?, ?, ?, ?, 'pending', ?, ?, ?)`,
28366
+ durability.toolCallId,
28367
+ request.tool,
28368
+ JSON.stringify(request.args ?? {}),
28369
+ request.requestPermission ?? null,
28370
+ typeof request.risk === "number" ? request.risk : null,
28371
+ durability.side,
28372
+ Date.now(),
28373
+ fenced ? ownerId : null,
28374
+ fenced ? owner.generation : 0
28375
+ );
28376
+ } catch (error) {
28377
+ console.error("[DurableThread] Failed to persist fast-path call (continuing):", error);
28378
+ }
28379
+ }
28380
+ const id = durability?.toolCallId ?? crypto.randomUUID();
28352
28381
  const timeoutMs = typeof request.timeoutMs === "number" && request.timeoutMs > 0 ? request.timeoutMs : DEFAULT_CLIENT_TOOL_TIMEOUT_MS;
28353
28382
  this.bridgeLastSeen.set(socket, Date.now());
28354
28383
  return new Promise((resolve2) => {
@@ -28399,6 +28428,13 @@ ${resultContent}${attachmentSummary}`;
28399
28428
  this.pendingClientCalls.delete(id);
28400
28429
  if (pending.timer) clearTimeout(pending.timer);
28401
28430
  if (pending.liveness) clearInterval(pending.liveness);
28431
+ try {
28432
+ void this.ctx.storage.sql.exec(
28433
+ `UPDATE pending_client_calls SET status = 'resolved' WHERE tool_call_id = ? AND status = 'pending'`,
28434
+ id
28435
+ );
28436
+ } catch {
28437
+ }
28402
28438
  pending.resolve(res);
28403
28439
  }
28404
28440
  /** Close and forget a bridge socket we've deemed dead, failing remaining calls. */
@@ -28650,6 +28686,26 @@ ${resultContent}${attachmentSummary}`;
28650
28686
  toolStatus,
28651
28687
  toolCallId
28652
28688
  );
28689
+ const updated = await this.ctx.storage.sql.exec(
28690
+ `SELECT COUNT(*) AS total FROM messages WHERE tool_call_id = ? AND role = 'tool'`,
28691
+ toolCallId
28692
+ );
28693
+ if (Number(updated.toArray()[0]?.total ?? 0) === 0) {
28694
+ const toolRow = await this.ctx.storage.sql.exec(
28695
+ `SELECT tool FROM pending_client_calls WHERE tool_call_id = ? LIMIT 1`,
28696
+ toolCallId
28697
+ );
28698
+ await this.ctx.storage.sql.exec(
28699
+ `INSERT INTO messages (id, role, content, name, tool_call_id, tool_status, created_at, status, prompt)
28700
+ VALUES (?, 'tool', ?, ?, ?, ?, ?, 'completed', NULL)`,
28701
+ crypto.randomUUID(),
28702
+ content,
28703
+ toolRow.toArray()[0]?.tool ?? null,
28704
+ toolCallId,
28705
+ toolStatus,
28706
+ Date.now() * TIMESTAMP_MULTIPLIER
28707
+ );
28708
+ }
28653
28709
  await this.ctx.storage.sql.exec(
28654
28710
  `UPDATE pending_client_calls SET status = 'resolved' WHERE tool_call_id = ?`,
28655
28711
  toolCallId
@@ -29587,6 +29643,31 @@ ${resultContent}${attachmentSummary}`;
29587
29643
  `SELECT COUNT(*) AS c FROM message_queue`
29588
29644
  )).toArray()[0]?.c ?? 0;
29589
29645
  if (stopped || finalizedCount === 0 && queued === 0) {
29646
+ let orphanedClientCalls = false;
29647
+ if (!stopped) {
29648
+ try {
29649
+ orphanedClientCalls = await this.hasInFlightClientCalls();
29650
+ } catch {
29651
+ orphanedClientCalls = false;
29652
+ }
29653
+ }
29654
+ if (orphanedClientCalls) {
29655
+ const owner = await this.getExecutionOwner();
29656
+ const socket = this.getOpenBridgeSocket(owner?.client_id ?? null);
29657
+ if (socket) {
29658
+ void this.resendPendingClientCalls(socket);
29659
+ } else if (threadId) {
29660
+ try {
29661
+ const meta = await this.getThreadMetadata(threadId);
29662
+ if (meta.user_id) await this.requestHubWake(meta.user_id, threadId);
29663
+ } catch {
29664
+ }
29665
+ }
29666
+ console.warn(
29667
+ `[DurableThread] Watchdog: pending forwarded call with no executor on ${threadId} \u2014 ${socket ? "re-dispatched to the connected bridge" : "requested owner wake"}`
29668
+ );
29669
+ return report("observing", "none", { queuedMessages: queued });
29670
+ }
29590
29671
  if (finalizedCount > 0) {
29591
29672
  return report("parked", "finalized_parked", {
29592
29673
  queuedMessages: queued,