agent-lattice 0.19.0 → 0.21.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/README.md +157 -1
- package/dist/index.d.ts +75 -3
- package/dist/index.js +7 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -86,7 +86,7 @@ them, so keep expensive handling off the loop itself.
|
|
|
86
86
|
| `stream_event` | While the model is responding | Raw provider stream event for incremental rendering. |
|
|
87
87
|
| `assistant` | After each model turn is assembled | The `AssistantModelMessage` with text / `tool_use` blocks and provider metadata. |
|
|
88
88
|
| `user` | After a whole tool batch finishes | Tool results as `ToolResultBlock[]`; the prompt is never echoed. |
|
|
89
|
-
| `result` | Once, at the end of the query | Final text, `subtype` (`"success"`, `"interrupted"`, or an error variant), and token usage. |
|
|
89
|
+
| `result` | Once, at the end of the query | Final text, `subtype` (`"success"`, `"interrupted"`, or an error variant), optional `structuredResult`, and token usage. |
|
|
90
90
|
|
|
91
91
|
For the exact per-event guarantees see
|
|
92
92
|
[Streaming Events](https://docs.claude-code-sdk.com/concepts/streaming-events/).
|
|
@@ -150,6 +150,14 @@ Anthropic-compatible providers (for example DeepSeek's
|
|
|
150
150
|
`https://api.deepseek.com/anthropic` endpoint) default thinking to on —
|
|
151
151
|
omitting the field would leave it enabled.
|
|
152
152
|
|
|
153
|
+
On DeepSeek, the on/off switch is the only thinking control that works:
|
|
154
|
+
DeepSeek accepts `budget_tokens` but ignores the value, treats `adaptive` as
|
|
155
|
+
plain enabled thinking, and does not support `reasoning_effort` at all. Its own
|
|
156
|
+
thinking-strength knob is `output_config.effort`, which the SDK does not expose
|
|
157
|
+
yet. See
|
|
158
|
+
[Provider Compatibility](https://docs.claude-code-sdk.com/reference/provider-compatibility/)
|
|
159
|
+
for the full matrix.
|
|
160
|
+
|
|
153
161
|
For Kimi K3 through an Anthropic-compatible endpoint or gateway, use
|
|
154
162
|
`reasoningEffort` to send the provider's top-level `reasoning_effort` parameter:
|
|
155
163
|
|
|
@@ -415,6 +423,12 @@ const agent = createAgent({
|
|
|
415
423
|
});
|
|
416
424
|
```
|
|
417
425
|
|
|
426
|
+
Pass an explicit `deepseek-*` model name — unknown names are silently mapped to
|
|
427
|
+
`deepseek-v4-flash`. For which SDK options DeepSeek actually honors (thinking
|
|
428
|
+
budgets are ignored; `reasoningEffort` does not apply; structured output is not
|
|
429
|
+
supported), see
|
|
430
|
+
[Provider Compatibility](https://docs.claude-code-sdk.com/reference/provider-compatibility/).
|
|
431
|
+
|
|
418
432
|
## Custom Tool
|
|
419
433
|
|
|
420
434
|
```ts
|
|
@@ -462,6 +476,148 @@ started concurrently, their `tool_result` blocks still enter the history, and
|
|
|
462
476
|
model call is skipped. When several tools in a batch set `endTurn`, the first
|
|
463
477
|
one's content becomes the result text.
|
|
464
478
|
|
|
479
|
+
A tool can also return `structuredResult` next to `endTurn: true` to carry a
|
|
480
|
+
structured payload to `SDKResultMessage.structuredResult`
|
|
481
|
+
(*requires 0.20.0 or later*). Without `endTurn`, `structuredResult` is
|
|
482
|
+
ignored.
|
|
483
|
+
|
|
484
|
+
## Structured Output Via submit_output
|
|
485
|
+
|
|
486
|
+
*Requires 0.20.0 or later.*
|
|
487
|
+
|
|
488
|
+
Set `AgentOptions.outputSchema` when a run must deliver a typed result rather
|
|
489
|
+
than free text. The SDK injects a built-in `submit_output` tool (exported as
|
|
490
|
+
`SUBMIT_OUTPUT_TOOL_NAME`) whose input schema is your schema converted to JSON
|
|
491
|
+
Schema — a zod schema works directly, since `OutputSchema<T>` is just
|
|
492
|
+
`{ parse(input: unknown): T }`:
|
|
493
|
+
|
|
494
|
+
```ts
|
|
495
|
+
import { createAgent } from "agent-lattice";
|
|
496
|
+
import { z } from "zod/v4";
|
|
497
|
+
|
|
498
|
+
const reviewSchema = z.object({
|
|
499
|
+
approved: z.boolean(),
|
|
500
|
+
issues: z.array(z.string()),
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
const reviewer = createAgent({
|
|
504
|
+
model: "claude-sonnet-4-6",
|
|
505
|
+
systemPrompt: "Review the change and submit your verdict.",
|
|
506
|
+
outputSchema: reviewSchema,
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
const result = await reviewer.prompt("Review the patch in this workspace.");
|
|
510
|
+
if (result.subtype === "success") {
|
|
511
|
+
console.log(result.structuredResult); // { approved: false, issues: [...] }
|
|
512
|
+
}
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
The structure is enforced by the harness, not by prompt discipline:
|
|
516
|
+
|
|
517
|
+
- The model submits its answer by calling `submit_output`. The payload is
|
|
518
|
+
validated against the schema first; a validation failure goes back into the
|
|
519
|
+
loop as an error `tool_result`, so the model can fix it and retry. A valid
|
|
520
|
+
submission ends the run with `subtype: "success"` and the payload on
|
|
521
|
+
`SDKResultMessage.structuredResult`.
|
|
522
|
+
- If the model ends its turn without calling `submit_output`, the run fails
|
|
523
|
+
with `subtype: "error_missing_output"` and a `MissingOutputError`. There is
|
|
524
|
+
no fallback that parses the final text as JSON.
|
|
525
|
+
- `submit_output` must be the only tool call in its batch. A batch that mixes
|
|
526
|
+
it with other calls — or contains two submissions — is rejected with code
|
|
527
|
+
`submit_output_exclusive_batch` and the loop continues.
|
|
528
|
+
- The name is reserved: registering your own `submit_output` tool while
|
|
529
|
+
`outputSchema` is set throws from `createAgent`/`addTools`.
|
|
530
|
+
|
|
531
|
+
Unlike `outputFormat` (which relies on the provider's
|
|
532
|
+
`response_format`/`json_schema` support — DeepSeek ignores it, see
|
|
533
|
+
[Provider Compatibility](https://docs.claude-code-sdk.com/reference/provider-compatibility/)),
|
|
534
|
+
`submit_output` only requires a model that can call tools, so it ports to any
|
|
535
|
+
tool-capable provider.
|
|
536
|
+
|
|
537
|
+
The same schema composes with `agentTool()` for parent/child delegation: give
|
|
538
|
+
it to the child agent, and an `ask` call returns the child's validated output
|
|
539
|
+
as a JSON string. Since 0.21.0 the parent side inherits the child's declared
|
|
540
|
+
schema, so the `agentTool()` copy can be omitted. Passing
|
|
541
|
+
`AgentToolOptions.outputSchema` explicitly is still allowed, but it must match
|
|
542
|
+
the target's declaration (compared by reference, then by derived JSON Schema
|
|
543
|
+
structure) — a mismatch throws at assembly time, so drift fails fast instead
|
|
544
|
+
of at call time. The error message suggests sharing one schema instance or
|
|
545
|
+
omitting the `agentTool()` copy:
|
|
546
|
+
|
|
547
|
+
```ts
|
|
548
|
+
import { agentTool, createAgent } from "agent-lattice";
|
|
549
|
+
|
|
550
|
+
const child = createAgent({
|
|
551
|
+
model: "claude-sonnet-4-5",
|
|
552
|
+
systemPrompt: "You review code and submit a structured verdict.",
|
|
553
|
+
outputSchema: reviewSchema, // child submits via submit_output
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
const parent = createAgent({
|
|
557
|
+
model: "claude-sonnet-4-6",
|
|
558
|
+
tools: [
|
|
559
|
+
agentTool("review", child, {
|
|
560
|
+
description: "Ask the reviewer to audit a change.",
|
|
561
|
+
// outputSchema is inherited from the child (0.21.0+); an explicit copy
|
|
562
|
+
// must match the child's declaration or agentTool() throws.
|
|
563
|
+
}),
|
|
564
|
+
],
|
|
565
|
+
});
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
If the child ends without submitting or submits a payload that fails the
|
|
569
|
+
schema, the tool returns an `is_error` `tool_result` starting with
|
|
570
|
+
`child_output_invalid:`, so the parent model sees the failure and can retry.
|
|
571
|
+
|
|
572
|
+
*Behavior change in 0.21.0:* where the child declares an `outputSchema` and
|
|
573
|
+
the parent does not, the `ask` tool result changed from the fixed text
|
|
574
|
+
`"Structured output submitted."` to the validated JSON. That is the intended
|
|
575
|
+
fix and ships in a minor under 0.x. Host-defined `AgentLike` adapters carry no
|
|
576
|
+
readable declaration, so nothing is inherited or cross-checked for them; an
|
|
577
|
+
explicit `outputSchema` still applies. Whenever a schema is in effect, the
|
|
578
|
+
generated tool description states that the tool returns the target's
|
|
579
|
+
validated structured output as JSON.
|
|
580
|
+
|
|
581
|
+
### Typed delegation
|
|
582
|
+
|
|
583
|
+
*Requires 0.21.0 or later.*
|
|
584
|
+
|
|
585
|
+
`AgentToolOptions.inputSchema` replaces the default `{mode, task,
|
|
586
|
+
expectedOutput, acceptanceCriteria, workspaceGrants}` input shape with your
|
|
587
|
+
own schema (a zod schema works directly), and `mapInput` projects the
|
|
588
|
+
validated input into the child prompt:
|
|
589
|
+
|
|
590
|
+
```ts
|
|
591
|
+
const judge = createAgent({
|
|
592
|
+
model: "claude-sonnet-4-5",
|
|
593
|
+
systemPrompt: "You judge a case and submit a structured verdict.",
|
|
594
|
+
outputSchema: verdictSchema,
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
const judgeTool = agentTool("judge", judge, {
|
|
598
|
+
description: "Judge a case from its summary and documents.",
|
|
599
|
+
inputSchema: z.object({
|
|
600
|
+
caseSummary: z.string(),
|
|
601
|
+
documents: z.array(z.object({ title: z.string(), content: z.string() })),
|
|
602
|
+
}),
|
|
603
|
+
mapInput: input => renderJudgeTask(input.caseSummary, input.documents),
|
|
604
|
+
});
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
- The parent's arguments are parsed against `inputSchema` before anything
|
|
608
|
+
runs; invalid input is rejected as an error `tool_result` in the parent's
|
|
609
|
+
loop — the same semantics as a plain `tool()` call — and the child is never
|
|
610
|
+
invoked.
|
|
611
|
+
- `inputSchema` and `mapInput` must come as a pair: `agentTool()` throws at
|
|
612
|
+
assembly time when one is missing.
|
|
613
|
+
- Typed delegation is ask-only: there is no `mode` field and no
|
|
614
|
+
`workspaceGrants`.
|
|
615
|
+
- `mapInput` may return a string or `ContentBlock[]`; `ContentBlock[]` is only
|
|
616
|
+
supported for direct `ask` calls — inside a team runtime the projected
|
|
617
|
+
prompt must be a string, or the call fails at runtime.
|
|
618
|
+
- Because typed input no longer matches `AgentToolInput`, `agentTool()` now
|
|
619
|
+
returns `ToolDefinition<any>`.
|
|
620
|
+
|
|
465
621
|
## Concurrent Tool Calls
|
|
466
622
|
|
|
467
623
|
The model requests concurrency by returning multiple `tool_use` blocks in one
|
package/dist/index.d.ts
CHANGED
|
@@ -70,7 +70,7 @@ export type AgentRuntimeDelegateResult = {
|
|
|
70
70
|
workspaceGrants?: WorkspaceGrant[];
|
|
71
71
|
};
|
|
72
72
|
export type AgentRuntimeFailure = {
|
|
73
|
-
code: "max_turns_exceeded" | "api_error" | "tool_execution_error" | "permission_denied" | "agent_error";
|
|
73
|
+
code: "max_turns_exceeded" | "api_error" | "tool_execution_error" | "permission_denied" | "missing_output" | "agent_error";
|
|
74
74
|
message: string;
|
|
75
75
|
name: string;
|
|
76
76
|
};
|
|
@@ -263,6 +263,11 @@ export type ToolResult = {
|
|
|
263
263
|
content: string | ContentBlock[];
|
|
264
264
|
/** End the run after this tool batch: finish with subtype "success" instead of calling the model again. */
|
|
265
265
|
endTurn?: boolean;
|
|
266
|
+
/**
|
|
267
|
+
* Structured payload carried to `SDKResultMessage.structuredResult` when this
|
|
268
|
+
* tool also ends the run with `endTurn`. Ignored otherwise.
|
|
269
|
+
*/
|
|
270
|
+
structuredResult?: unknown;
|
|
266
271
|
};
|
|
267
272
|
export type ToolKind = "tool" | "agent_tool";
|
|
268
273
|
export type ToolBatchCall = {
|
|
@@ -581,6 +586,16 @@ export type AgentOptions<TContext = unknown> = {
|
|
|
581
586
|
requestTimeoutMs?: number;
|
|
582
587
|
tools?: Array<ToolDefinition<any, TContext>>;
|
|
583
588
|
toolBatchPolicy?: ToolBatchPolicy<TContext>;
|
|
589
|
+
/**
|
|
590
|
+
* Declares the run's structured output contract. When set, the SDK injects a
|
|
591
|
+
* `submit_output` tool with this schema: the run only ends successfully once
|
|
592
|
+
* the model submits a payload through it, and the validated payload lands on
|
|
593
|
+
* `SDKResultMessage.structuredResult`. Ending the turn without submitting
|
|
594
|
+
* fails the run with subtype `error_missing_output`. The tool must be the
|
|
595
|
+
* only call in its batch, and its name is reserved (registering a user tool
|
|
596
|
+
* with the same name throws).
|
|
597
|
+
*/
|
|
598
|
+
outputSchema?: OutputSchema;
|
|
584
599
|
/** Lifecycle callbacks that rewrite tool results and outgoing model requests. */
|
|
585
600
|
hooks?: AgentHooks<TContext>;
|
|
586
601
|
/**
|
|
@@ -682,12 +697,18 @@ export type SDKResultMessage = {
|
|
|
682
697
|
* way, keeping completed turns in history so a follow-up query can continue
|
|
683
698
|
* the conversation. `is_error` stays `false` for it.
|
|
684
699
|
*/
|
|
685
|
-
subtype: "success" | "interrupted" | "error" | "error_max_turns" | "error_abort" | "error_timeout";
|
|
700
|
+
subtype: "success" | "interrupted" | "error" | "error_max_turns" | "error_abort" | "error_timeout" | "error_missing_output";
|
|
686
701
|
is_error: boolean;
|
|
687
702
|
result: string;
|
|
688
703
|
session_id: string;
|
|
689
704
|
num_turns: number;
|
|
690
705
|
error?: Error;
|
|
706
|
+
/**
|
|
707
|
+
* Validated structured payload submitted via the `submit_output` tool (see
|
|
708
|
+
* `AgentOptions.outputSchema`), or by any tool that ended the run with both
|
|
709
|
+
* `endTurn` and `ToolResult.structuredResult`. Absent otherwise.
|
|
710
|
+
*/
|
|
711
|
+
structuredResult?: unknown;
|
|
691
712
|
/** Summed over every model request in the query. Zeroed when unreported. */
|
|
692
713
|
usage: TokenUsage;
|
|
693
714
|
/**
|
|
@@ -734,6 +755,12 @@ export declare class ToolExecutionError extends AgentSDKError {
|
|
|
734
755
|
}
|
|
735
756
|
export declare class MaxTurnsError extends AgentSDKError {
|
|
736
757
|
}
|
|
758
|
+
/**
|
|
759
|
+
* A run with `AgentOptions.outputSchema` ended without the model calling the
|
|
760
|
+
* `submit_output` tool, so no structured output was produced.
|
|
761
|
+
*/
|
|
762
|
+
export declare class MissingOutputError extends AgentSDKError {
|
|
763
|
+
}
|
|
737
764
|
export declare class AbortError extends AgentSDKError {
|
|
738
765
|
}
|
|
739
766
|
/** A second query was started on an Agent that was still running one. */
|
|
@@ -752,6 +779,20 @@ export declare class ToolPermissionDeniedError extends AgentSDKError {
|
|
|
752
779
|
}
|
|
753
780
|
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>;
|
|
754
781
|
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>;
|
|
782
|
+
/**
|
|
783
|
+
* A schema describing structured output: a zod schema, or any object with a
|
|
784
|
+
* compatible `parse` method. The SDK validates submitted payloads with it and
|
|
785
|
+
* converts it to the JSON schema shown to the model.
|
|
786
|
+
*/
|
|
787
|
+
export type OutputSchema<TOutput = unknown> = {
|
|
788
|
+
parse(input: unknown): TOutput;
|
|
789
|
+
};
|
|
790
|
+
/**
|
|
791
|
+
* Name of the tool the SDK injects when `AgentOptions.outputSchema` is set.
|
|
792
|
+
* Reserved in that configuration: registering a user tool with the same name
|
|
793
|
+
* throws at `createAgent`/`addTools` time.
|
|
794
|
+
*/
|
|
795
|
+
export declare const SUBMIT_OUTPUT_TOOL_NAME = "submit_output";
|
|
755
796
|
export type DelegateToolOptions = {
|
|
756
797
|
wait?: DelegateWaitMode;
|
|
757
798
|
targetMailboxId?: string;
|
|
@@ -780,6 +821,35 @@ export type AgentToolInput = z.infer<typeof agentToolInputSchema>;
|
|
|
780
821
|
export type AgentToolOptions = {
|
|
781
822
|
description: string;
|
|
782
823
|
targetMailboxId?: string;
|
|
824
|
+
/**
|
|
825
|
+
* Expected structured output of the target. When omitted, the declaration is
|
|
826
|
+
* inherited from the target itself (an Agent's or AgentSpec's
|
|
827
|
+
* `AgentOptions.outputSchema`); when passed explicitly it must match the
|
|
828
|
+
* target's declaration or `agentTool()` throws at assembly time. Host-defined
|
|
829
|
+
* AgentLike adapters carry no readable declaration, so nothing is inherited
|
|
830
|
+
* or cross-checked for them.
|
|
831
|
+
*
|
|
832
|
+
* With the schema in effect, the tool result is the target's validated
|
|
833
|
+
* structured output as JSON; a target that ends without submitting — or
|
|
834
|
+
* submits a payload that fails the schema — produces a `child_output_invalid`
|
|
835
|
+
* tool error the parent can retry.
|
|
836
|
+
*/
|
|
837
|
+
outputSchema?: OutputSchema;
|
|
838
|
+
/**
|
|
839
|
+
* Typed delegation: replaces the default `{mode, task, ...}` input shape
|
|
840
|
+
* with this schema (same structural shape as OutputSchema; a zod schema
|
|
841
|
+
* works directly). The parent's arguments are validated before the child is
|
|
842
|
+
* invoked, and `mapInput` projects the validated input into the child
|
|
843
|
+
* prompt. Typed delegation is ask-only: there is no `mode` field and no
|
|
844
|
+
* `workspaceGrants`. Requires `mapInput`.
|
|
845
|
+
*/
|
|
846
|
+
inputSchema?: OutputSchema;
|
|
847
|
+
/**
|
|
848
|
+
* Projects validated `inputSchema` input into the child prompt. Returning
|
|
849
|
+
* `ContentBlock[]` is only supported for direct ask calls; inside a team
|
|
850
|
+
* runtime the projected prompt must be a string.
|
|
851
|
+
*/
|
|
852
|
+
mapInput?: (input: any) => string | ContentBlock[];
|
|
783
853
|
};
|
|
784
854
|
/**
|
|
785
855
|
* An AgentLike is a live session: it keeps its conversation history across
|
|
@@ -788,7 +858,7 @@ export type AgentToolOptions = {
|
|
|
788
858
|
* continuity.
|
|
789
859
|
*/
|
|
790
860
|
export type AgentToolTarget = AgentLike<any> | AgentSpec<any>;
|
|
791
|
-
export declare function agentTool(name: string, agent: AgentToolTarget, options: AgentToolOptions): ToolDefinition<
|
|
861
|
+
export declare function agentTool(name: string, agent: AgentToolTarget, options: AgentToolOptions): ToolDefinition<any>;
|
|
792
862
|
export declare function delegateTool(name: string, description: string, agent: AgentToolTarget, options?: DelegateToolOptions): ToolDefinition<{
|
|
793
863
|
task: string;
|
|
794
864
|
}>;
|
|
@@ -938,6 +1008,8 @@ declare class Agent<TContext = unknown> {
|
|
|
938
1008
|
*/
|
|
939
1009
|
replaceHistory(messages: ModelMessage[]): Promise<void>;
|
|
940
1010
|
addTools(tools: Array<ToolDefinition<any, TContext>>): void;
|
|
1011
|
+
/** The structured output contract declared via `AgentOptions.outputSchema`, if any. */
|
|
1012
|
+
get outputSchema(): OutputSchema | undefined;
|
|
941
1013
|
private initMessage;
|
|
942
1014
|
private resultMessage;
|
|
943
1015
|
private modelTools;
|