agent-lattice 0.9.24 → 0.9.25

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/README.md CHANGED
@@ -230,9 +230,13 @@ const tracer = createLangSmithContextTracer({
230
230
  });
231
231
  ```
232
232
 
233
- LangSmith receives one root `chain` run per SDK query, child `llm` runs for
234
- model turns, child `tool` runs for SDK tool calls, and run events for auxiliary
235
- trace events.
233
+ LangSmith receives one root `chain` run per SDK query. For an `Agent` query,
234
+ model turns and SDK tool calls appear as child `llm` and `tool` runs. For a
235
+ `Team` query, the root represents the complete Team invocation; the initial
236
+ Lead run, delegated Member runs, and later Lead runs all appear beneath that
237
+ root and share one trace session. Each Agent keeps its own SDK session identity,
238
+ recorded as `agent_session_id` metadata, so tracing does not change Agent state
239
+ or returned SDK messages.
236
240
 
237
241
  Custom sinks can implement the same interface for SQLite, OpenTelemetry, object
238
242
  storage, or host-specific observability. The functions below are application
@@ -283,6 +287,47 @@ const result = await agent.prompt("What is 2+2?");
283
287
  console.log(result.result);
284
288
  ```
285
289
 
290
+ ## Concurrent Tool Calls
291
+
292
+ The model requests concurrency by returning multiple `tool_use` blocks in one
293
+ assistant message. The SDK makes the final safety decision. By default, only
294
+ tools whose parsed input passes `isConcurrencySafe(input)` run together:
295
+
296
+ ```ts
297
+ const search = tool(
298
+ "search",
299
+ "Search documents",
300
+ z.object({ query: z.string() }),
301
+ async ({ query }) => {
302
+ // App code: replace with your database or search client.
303
+ return { content: await documentIndex.search(query) };
304
+ },
305
+ { isConcurrencySafe: () => true },
306
+ );
307
+
308
+ const agent = createAgent({
309
+ model: "claude-sonnet-4-6",
310
+ tools: [search],
311
+ toolConcurrency: { mode: "safe", maxConcurrency: 8 },
312
+ });
313
+ ```
314
+
315
+ `safe` is the default mode, `maxConcurrency` defaults to `10`, and tools without
316
+ an `isConcurrencySafe` declaration stay sequential. Use `mode: "all"` only when
317
+ every tool in the Agent is safe to overlap. Use `mode: "sequential"` to disable
318
+ tool concurrency even for tools marked safe.
319
+
320
+ When concurrency is available, the SDK tells the model to batch independent
321
+ calls and to use separate assistant responses when a later call needs an earlier
322
+ result. Runtime safety checks and `toolBatchPolicy` remain authoritative.
323
+
324
+ The SDK waits for the complete batch before requesting the model again. Tools
325
+ may finish in any order, while the `tool_result` blocks sent to the model remain
326
+ in the original `tool_use` order. One tool failure does not discard the other
327
+ results. On abort, running handlers receive the shared `AbortSignal`, queued
328
+ handlers do not start, and the SDK waits for handlers that already started to
329
+ settle.
330
+
286
331
  ## Tool Batch Policy
287
332
 
288
333
  Use `toolBatchPolicy` when some tools must not run in the same model response.
package/dist/index.d.ts CHANGED
@@ -211,6 +211,9 @@ export type ToolExecutionContext<TContext = unknown> = {
211
211
  permissions?: RuntimePermissions;
212
212
  };
213
213
  export type ToolHandler<TInput = unknown, TContext = unknown> = (input: TInput, context: ToolExecutionContext<TContext>) => Promise<ToolResult> | ToolResult;
214
+ export type ToolOptions<TInput = unknown> = {
215
+ isConcurrencySafe?: (input: TInput) => boolean;
216
+ };
214
217
  export type ToolDefinition<TInput = unknown, TContext = unknown> = {
215
218
  name: string;
216
219
  description: string;
@@ -219,6 +222,12 @@ export type ToolDefinition<TInput = unknown, TContext = unknown> = {
219
222
  jsonSchema: Record<string, unknown>;
220
223
  parse(input: unknown): TInput;
221
224
  handler: ToolHandler<TInput, TContext>;
225
+ isConcurrencySafe?: (input: TInput) => boolean;
226
+ };
227
+ export type ToolConcurrencyMode = "safe" | "all" | "sequential";
228
+ export type ToolConcurrencyOptions = {
229
+ mode?: ToolConcurrencyMode;
230
+ maxConcurrency?: number;
222
231
  };
223
232
  export type SkillDefinition = {
224
233
  name: string;
@@ -414,6 +423,7 @@ export type AgentOptions<TContext = unknown> = {
414
423
  thinkingConfig?: ThinkingConfig;
415
424
  tools?: Array<ToolDefinition<any, TContext>>;
416
425
  toolBatchPolicy?: ToolBatchPolicy<TContext>;
426
+ toolConcurrency?: ToolConcurrencyOptions;
417
427
  skills?: SkillDefinition[];
418
428
  workspace?: AgentWorkspaceOptions;
419
429
  permission?: (request: PermissionRequest) => Promise<PermissionDecision> | PermissionDecision;
@@ -526,8 +536,8 @@ export declare class ToolPermissionDeniedError extends AgentSDKError {
526
536
  readonly denial: PermissionDenial;
527
537
  constructor(denial: PermissionDenial);
528
538
  }
529
- export declare function tool<TContext = unknown>(): <TSchema>(name: string, description: string, inputSchema: TSchema, handler: ToolHandler<InferInput<TSchema>, TContext>) => ToolDefinition<InferInput<TSchema>, TContext>;
530
- export declare function tool<TSchema, TContext = unknown>(name: string, description: string, inputSchema: TSchema, handler: ToolHandler<InferInput<TSchema>, TContext>): ToolDefinition<InferInput<TSchema>, TContext>;
539
+ export declare function tool<TContext = unknown>(): <TSchema>(name: string, description: string, inputSchema: TSchema, handler: ToolHandler<InferInput<TSchema>, TContext>, options?: ToolOptions<InferInput<TSchema>>) => ToolDefinition<InferInput<TSchema>, TContext>;
540
+ export declare function tool<TSchema, TContext = unknown>(name: string, description: string, inputSchema: TSchema, handler: ToolHandler<InferInput<TSchema>, TContext>, options?: ToolOptions<InferInput<TSchema>>): ToolDefinition<InferInput<TSchema>, TContext>;
531
541
  export type DelegateToolOptions = {
532
542
  wait?: DelegateWaitMode;
533
543
  targetMailboxId?: string;
@@ -591,6 +601,7 @@ export declare class Agent<TContext = unknown> {
591
601
  private readonly modelClient;
592
602
  private readonly messages;
593
603
  private readonly sessionId;
604
+ private readonly toolConcurrency;
594
605
  constructor(options: AgentOptions<TContext>);
595
606
  query(prompt: string | ContentBlock[], options?: QueryOptions<TContext>): AsyncGenerator<SDKMessage>;
596
607
  prompt(prompt: string | ContentBlock[], options?: QueryOptions<TContext>): Promise<SDKResultMessage>;
@@ -601,6 +612,8 @@ export declare class Agent<TContext = unknown> {
601
612
  private messagesForModel;
602
613
  private selectSkills;
603
614
  private runTool;
615
+ private executeToolBatch;
616
+ private isToolCallConcurrencySafe;
604
617
  }
605
618
  type InferInput<TSchema> = TSchema extends {
606
619
  parse(input: unknown): infer TInput;