agent-lattice 0.9.23 → 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 +89 -3
- package/dist/index.d.ts +47 -2
- package/dist/index.js +7 -7
- package/package.json +1 -1
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
|
|
234
|
-
model turns
|
|
235
|
-
|
|
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,88 @@ 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
|
+
|
|
331
|
+
## Tool Batch Policy
|
|
332
|
+
|
|
333
|
+
Use `toolBatchPolicy` when some tools must not run in the same model response.
|
|
334
|
+
The policy sees the complete batch before any tool executes. If it rejects the
|
|
335
|
+
batch, no tool runs and every tool call receives a structured `is_error: true`
|
|
336
|
+
result.
|
|
337
|
+
|
|
338
|
+
```ts
|
|
339
|
+
const lead = createAgent({
|
|
340
|
+
model: "claude-sonnet-4-6",
|
|
341
|
+
tools: [incrementRevision],
|
|
342
|
+
toolBatchPolicy: {
|
|
343
|
+
validate({ toolCalls }) {
|
|
344
|
+
const incrementsRevision = toolCalls.find(
|
|
345
|
+
call => call.name === "incrementRevision",
|
|
346
|
+
);
|
|
347
|
+
const handoff = toolCalls.find(
|
|
348
|
+
call => call.kind === "agent_tool" &&
|
|
349
|
+
(call.input as { mode?: string }).mode === "handoff",
|
|
350
|
+
);
|
|
351
|
+
if (incrementsRevision && handoff) {
|
|
352
|
+
return {
|
|
353
|
+
allowed: false,
|
|
354
|
+
code: "invalid_tool_batch",
|
|
355
|
+
message: "Update the revision before delegating dependent work.",
|
|
356
|
+
conflictingToolCallIds: [incrementsRevision.id, handoff.id],
|
|
357
|
+
suggestedNextStep: "Run incrementRevision first, then hand off the new revision.",
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
return { allowed: true };
|
|
361
|
+
},
|
|
362
|
+
},
|
|
363
|
+
});
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
The policy may be synchronous or asynchronous. If it throws, the SDK rejects
|
|
367
|
+
the whole batch with `tool_batch_policy_error`; no tool has executed. Without a
|
|
368
|
+
policy, tool execution is unchanged. A policy prevents known bad combinations
|
|
369
|
+
inside one model response, but it does not replace database transactions or
|
|
370
|
+
revision checks against concurrent external updates.
|
|
371
|
+
|
|
286
372
|
## Business Context For Tools
|
|
287
373
|
|
|
288
374
|
Pass host application data through `context`. The SDK gives that context to
|
package/dist/index.d.ts
CHANGED
|
@@ -177,6 +177,32 @@ export interface ModelClient {
|
|
|
177
177
|
export type ToolResult = {
|
|
178
178
|
content: string | ContentBlock[];
|
|
179
179
|
};
|
|
180
|
+
export type ToolKind = "tool" | "agent_tool";
|
|
181
|
+
export type ToolBatchCall = {
|
|
182
|
+
id: string;
|
|
183
|
+
name: string;
|
|
184
|
+
input: unknown;
|
|
185
|
+
kind: ToolKind;
|
|
186
|
+
};
|
|
187
|
+
export type ToolBatchPolicyContext<TContext = unknown> = {
|
|
188
|
+
source?: AgentRuntimeSource;
|
|
189
|
+
toolCalls: ToolBatchCall[];
|
|
190
|
+
context?: TContext;
|
|
191
|
+
signal?: AbortSignal;
|
|
192
|
+
};
|
|
193
|
+
export type ToolBatchPolicyRejection = {
|
|
194
|
+
allowed: false;
|
|
195
|
+
code: string;
|
|
196
|
+
message: string;
|
|
197
|
+
conflictingToolCallIds?: string[];
|
|
198
|
+
suggestedNextStep?: string;
|
|
199
|
+
};
|
|
200
|
+
export type ToolBatchPolicyResult = {
|
|
201
|
+
allowed: true;
|
|
202
|
+
} | ToolBatchPolicyRejection;
|
|
203
|
+
export type ToolBatchPolicy<TContext = unknown> = {
|
|
204
|
+
validate(context: ToolBatchPolicyContext<TContext>): ToolBatchPolicyResult | Promise<ToolBatchPolicyResult>;
|
|
205
|
+
};
|
|
180
206
|
export type ToolExecutionContext<TContext = unknown> = {
|
|
181
207
|
signal?: AbortSignal;
|
|
182
208
|
toolUseId: string;
|
|
@@ -185,13 +211,23 @@ export type ToolExecutionContext<TContext = unknown> = {
|
|
|
185
211
|
permissions?: RuntimePermissions;
|
|
186
212
|
};
|
|
187
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
|
+
};
|
|
188
217
|
export type ToolDefinition<TInput = unknown, TContext = unknown> = {
|
|
189
218
|
name: string;
|
|
190
219
|
description: string;
|
|
220
|
+
kind?: ToolKind;
|
|
191
221
|
inputSchema: unknown;
|
|
192
222
|
jsonSchema: Record<string, unknown>;
|
|
193
223
|
parse(input: unknown): TInput;
|
|
194
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;
|
|
195
231
|
};
|
|
196
232
|
export type SkillDefinition = {
|
|
197
233
|
name: string;
|
|
@@ -386,6 +422,8 @@ export type AgentOptions<TContext = unknown> = {
|
|
|
386
422
|
maxTurns?: number;
|
|
387
423
|
thinkingConfig?: ThinkingConfig;
|
|
388
424
|
tools?: Array<ToolDefinition<any, TContext>>;
|
|
425
|
+
toolBatchPolicy?: ToolBatchPolicy<TContext>;
|
|
426
|
+
toolConcurrency?: ToolConcurrencyOptions;
|
|
389
427
|
skills?: SkillDefinition[];
|
|
390
428
|
workspace?: AgentWorkspaceOptions;
|
|
391
429
|
permission?: (request: PermissionRequest) => Promise<PermissionDecision> | PermissionDecision;
|
|
@@ -490,12 +528,16 @@ export declare class MaxTurnsError extends AgentSDKError {
|
|
|
490
528
|
}
|
|
491
529
|
export declare class AbortError extends AgentSDKError {
|
|
492
530
|
}
|
|
531
|
+
export declare class ToolBatchRejectedError extends AgentSDKError {
|
|
532
|
+
readonly rejection: ToolBatchPolicyRejection;
|
|
533
|
+
constructor(rejection: ToolBatchPolicyRejection);
|
|
534
|
+
}
|
|
493
535
|
export declare class ToolPermissionDeniedError extends AgentSDKError {
|
|
494
536
|
readonly denial: PermissionDenial;
|
|
495
537
|
constructor(denial: PermissionDenial);
|
|
496
538
|
}
|
|
497
|
-
export declare function tool<TContext = unknown>(): <TSchema>(name: string, description: string, inputSchema: TSchema, handler: ToolHandler<InferInput<TSchema>, TContext
|
|
498
|
-
export declare function tool<TSchema, TContext = unknown>(name: string, description: string, inputSchema: TSchema, handler: ToolHandler<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>;
|
|
499
541
|
export type DelegateToolOptions = {
|
|
500
542
|
wait?: DelegateWaitMode;
|
|
501
543
|
targetMailboxId?: string;
|
|
@@ -559,6 +601,7 @@ export declare class Agent<TContext = unknown> {
|
|
|
559
601
|
private readonly modelClient;
|
|
560
602
|
private readonly messages;
|
|
561
603
|
private readonly sessionId;
|
|
604
|
+
private readonly toolConcurrency;
|
|
562
605
|
constructor(options: AgentOptions<TContext>);
|
|
563
606
|
query(prompt: string | ContentBlock[], options?: QueryOptions<TContext>): AsyncGenerator<SDKMessage>;
|
|
564
607
|
prompt(prompt: string | ContentBlock[], options?: QueryOptions<TContext>): Promise<SDKResultMessage>;
|
|
@@ -569,6 +612,8 @@ export declare class Agent<TContext = unknown> {
|
|
|
569
612
|
private messagesForModel;
|
|
570
613
|
private selectSkills;
|
|
571
614
|
private runTool;
|
|
615
|
+
private executeToolBatch;
|
|
616
|
+
private isToolCallConcurrencySafe;
|
|
572
617
|
}
|
|
573
618
|
type InferInput<TSchema> = TSchema extends {
|
|
574
619
|
parse(input: unknown): infer TInput;
|