Skip to content

Commit 7ebc562

Browse files
committed
Merge remote-tracking branch 'origin/main' into blove/home-stage-subagents
2 parents 0c6c631 + a386692 commit 7ebc562

46 files changed

Lines changed: 2700 additions & 236 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
1+
## Unreleased
2+
3+
### Features
4+
5+
- **ag-ui:** expose complete interrupt sessions, optional atomic persistence and authoritative recovery, and provider lifetime cleanup.
6+
7+
### Fixes
8+
9+
- **langgraph:** retain null-payload resume commands and combined message/state input for intentional retry without reusing an aborted signal.
10+
- **ag-ui:** retain exact resume decisions, roll failed state back to committed boundaries, and reject stale callbacks and concurrent recovery actions.
11+
12+
### Breaking changes
13+
14+
- **ag-ui:** native batches take precedence over compatibility events in `auto` mode. Select `legacy-command` or `mastra-command` explicitly for backends requiring command transport.
15+
- **ag-ui:** resume requires a pending batch and each native ID exactly once; scalar responses apply only to single-entry batches. New messages, regeneration, and client-tool continuation cannot abandon an unresolved interrupt.
16+
- **ag-ui:** uncertain resumes require authoritative reconciliation before retry. Durable client claims require an application-provided atomic store; backend duplicate-effect protection requires server idempotency.
17+
118
## 0.1.0 (2026-09-08)
219

320
### 🚀 Features

apps/website/content/docs/ag-ui/api/api-docs.json

Lines changed: 289 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,18 @@
387387
"description": "Extra HTTP headers sent with every request (e.g. auth tokens).",
388388
"optional": true
389389
},
390+
{
391+
"name": "interruptTransport",
392+
"type": "InterruptTransport",
393+
"description": "Explicit compatibility wire profile; auto prefers protocol-native outcomes.",
394+
"optional": true
395+
},
396+
{
397+
"name": "persistence",
398+
"type": "AgUiInterruptPersistence",
399+
"description": "Optional application-owned durable thread storage and reconciliation.",
400+
"optional": true
401+
},
390402
{
391403
"name": "telemetry",
392404
"type": "false | AgentRuntimeTelemetrySink",
@@ -440,7 +452,19 @@
440452
{
441453
"name": "interrupt",
442454
"type": "Signal<AgentInterrupt | undefined>",
443-
"description": "",
455+
"description": "Optional display projection of the pending interrupt. A runtime may expose\na separate full batch and lifecycle surface. A cleared display projection\ndoes not by itself prove that resumed backend work completed.",
456+
"optional": true
457+
},
458+
{
459+
"name": "interruptSession",
460+
"type": "Signal<InterruptSessionSnapshot>",
461+
"description": "Full interrupt batch and its request ownership phase.",
462+
"optional": false
463+
},
464+
{
465+
"name": "isInputBlocked",
466+
"type": "Signal<boolean>",
467+
"description": "Optional gate for ordinary composer input while the runtime requires resolution or recovery. Resume actions remain adapter-controlled.",
444468
"optional": true
445469
},
446470
{
@@ -455,6 +479,12 @@
455479
"description": "",
456480
"optional": false
457481
},
482+
{
483+
"name": "ready",
484+
"type": "Promise<void>",
485+
"description": "Resolves after persisted thread state is hydrated; actions wait for it.",
486+
"optional": false
487+
},
458488
{
459489
"name": "regenerate",
460490
"type": "(assistantMessageIndex: number) => Promise<void>",
@@ -464,7 +494,7 @@
464494
{
465495
"name": "retry",
466496
"type": "() => Promise<void>",
467-
"description": "Re-run the last submitted input after a failure. No-op if a run is already\n in flight or there is nothing to retry. Clears `error` and sets loading.",
497+
"description": "Re-run the captured submission after a failure, including a resume command\nwith no message payload. Does not append another user message or reuse an\naborted request signal. Does not restart an in-flight request; no-op when\nnothing is saved.\nAdapters may reject unsafe resume retries until the backend outcome has\nbeen reconciled; a transport failure alone does not prove non-execution.",
468498
"optional": false
469499
},
470500
{
@@ -492,16 +522,43 @@
492522
"optional": false
493523
},
494524
{
495-
"name": "submit",
496-
"type": "(input: AgentSubmitInput, opts: AgentSubmitOptions) => Promise<void>",
525+
"name": "toolCalls",
526+
"type": "Signal<ToolCall[]>",
497527
"description": "",
498528
"optional": false
529+
}
530+
],
531+
"methods": [
532+
{
533+
"name": "dispose",
534+
"signature": "dispose(): void",
535+
"description": "Unsubscribe and stop local work. Does not cancel backend checkpoints.",
536+
"params": []
499537
},
500538
{
501-
"name": "toolCalls",
502-
"type": "Signal<ToolCall[]>",
539+
"name": "reconcileInterrupt",
540+
"signature": "reconcileInterrupt(): Promise<void>",
541+
"description": "Recover an uncertain attempt using the configured authoritative reconciler.",
542+
"params": []
543+
},
544+
{
545+
"name": "submit",
546+
"signature": "submit(input: AgentSubmitInput, opts: AgUiSubmitOptions): Promise<void>",
503547
"description": "",
504-
"optional": false
548+
"params": [
549+
{
550+
"name": "input",
551+
"type": "AgentSubmitInput",
552+
"description": "",
553+
"optional": false
554+
},
555+
{
556+
"name": "opts",
557+
"type": "AgUiSubmitOptions",
558+
"description": "",
559+
"optional": true
560+
}
561+
]
505562
}
506563
],
507564
"examples": []
@@ -538,6 +595,102 @@
538595
],
539596
"examples": []
540597
},
598+
{
599+
"name": "AgUiInterruptPersistence",
600+
"kind": "interface",
601+
"description": "",
602+
"properties": [
603+
{
604+
"name": "namespace",
605+
"type": "string",
606+
"description": "",
607+
"optional": false
608+
},
609+
{
610+
"name": "reconcile",
611+
"type": "(record: AgUiThreadRecord) => Promise<object | object>",
612+
"description": "",
613+
"optional": true
614+
},
615+
{
616+
"name": "store",
617+
"type": "object",
618+
"description": "",
619+
"optional": false
620+
}
621+
],
622+
"examples": []
623+
},
624+
{
625+
"name": "AgUiSubmitOptions",
626+
"kind": "interface",
627+
"description": "Adapter-specific submit guards in addition to cancellation.",
628+
"properties": [
629+
{
630+
"name": "interruptGeneration",
631+
"type": "number",
632+
"description": "Generation captured when rendering the interrupt decision; rejects stale controls.",
633+
"optional": true
634+
},
635+
{
636+
"name": "signal",
637+
"type": "AbortSignal",
638+
"description": "",
639+
"optional": true
640+
}
641+
],
642+
"examples": []
643+
},
644+
{
645+
"name": "AgUiThreadRecord",
646+
"kind": "interface",
647+
"description": "",
648+
"properties": [
649+
{
650+
"name": "committed",
651+
"type": "ThreadSnapshot",
652+
"description": "",
653+
"optional": false
654+
},
655+
{
656+
"name": "namespace",
657+
"type": "string",
658+
"description": "",
659+
"optional": false
660+
},
661+
{
662+
"name": "resumeInput",
663+
"type": "ThreadSnapshot",
664+
"description": "",
665+
"optional": true
666+
},
667+
{
668+
"name": "revision",
669+
"type": "number",
670+
"description": "",
671+
"optional": false
672+
},
673+
{
674+
"name": "session",
675+
"type": "InterruptSessionSnapshot",
676+
"description": "",
677+
"optional": false
678+
},
679+
{
680+
"name": "threadId",
681+
"type": "string",
682+
"description": "",
683+
"optional": false
684+
},
685+
{
686+
"name": "version",
687+
"type": "1",
688+
"description": "",
689+
"optional": false
690+
}
691+
],
692+
"examples": []
693+
},
541694
{
542695
"name": "CustomStreamEvent",
543696
"kind": "interface",
@@ -558,6 +711,108 @@
558711
],
559712
"examples": []
560713
},
714+
{
715+
"name": "InterruptSessionSnapshot",
716+
"kind": "interface",
717+
"description": "",
718+
"properties": [
719+
{
720+
"name": "attempt",
721+
"type": "ResumeAttempt",
722+
"description": "",
723+
"optional": true
724+
},
725+
{
726+
"name": "generation",
727+
"type": "number",
728+
"description": "",
729+
"optional": false
730+
},
731+
{
732+
"name": "interrupts",
733+
"type": "object[]",
734+
"description": "",
735+
"optional": false
736+
},
737+
{
738+
"name": "legacy",
739+
"type": "AgentInterrupt",
740+
"description": "",
741+
"optional": true
742+
},
743+
{
744+
"name": "phase",
745+
"type": "InterruptSessionPhase",
746+
"description": "",
747+
"optional": false
748+
},
749+
{
750+
"name": "runId",
751+
"type": "string",
752+
"description": "",
753+
"optional": true
754+
}
755+
],
756+
"examples": []
757+
},
758+
{
759+
"name": "ResumeAttempt",
760+
"kind": "interface",
761+
"description": "",
762+
"properties": [
763+
{
764+
"name": "generation",
765+
"type": "number",
766+
"description": "",
767+
"optional": false
768+
},
769+
{
770+
"name": "id",
771+
"type": "string",
772+
"description": "",
773+
"optional": false
774+
},
775+
{
776+
"name": "input",
777+
"type": "AgentSubmitInput",
778+
"description": "",
779+
"optional": false
780+
},
781+
{
782+
"name": "parameters",
783+
"type": "object",
784+
"description": "",
785+
"optional": false
786+
},
787+
{
788+
"name": "runId",
789+
"type": "string",
790+
"description": "",
791+
"optional": false
792+
}
793+
],
794+
"examples": []
795+
},
796+
{
797+
"name": "ThreadSnapshot",
798+
"kind": "interface",
799+
"description": "Serializable protocol state at a confirmed run boundary.",
800+
"properties": [
801+
{
802+
"name": "messages",
803+
"type": "object | object | object | object | object | object | object[]",
804+
"description": "",
805+
"optional": false
806+
},
807+
{
808+
"name": "state",
809+
"type": "Record<string, unknown>",
810+
"description": "",
811+
"optional": false
812+
}
813+
],
814+
"examples": []
815+
},
561816
{
562817
"name": "ToAgentOptions",
563818
"kind": "interface",
@@ -569,6 +824,18 @@
569824
"description": "A2UI client capabilities (catalog negotiation) to advertise to the agent.\nWhen set, they are seeded once into the AG-UI shared state under the\n`a2ui_client_capabilities` key, so every RunAgentInput.state carries them.\nUse `@threadplane/chat`'s `a2uiClientCapabilities()` for the renderer's\nstandard value.",
570825
"optional": true
571826
},
827+
{
828+
"name": "interruptTransport",
829+
"type": "InterruptTransport",
830+
"description": "Native outcomes take precedence in auto mode; select a legacy profile explicitly when required.",
831+
"optional": true
832+
},
833+
{
834+
"name": "persistence",
835+
"type": "AgUiInterruptPersistence",
836+
"description": "Application-owned durable storage. Requires a stable source threadId and scoped namespace.",
837+
"optional": true
838+
},
572839
{
573840
"name": "telemetry",
574841
"type": "false | AgentRuntimeTelemetrySink",
@@ -585,6 +852,20 @@
585852
"signature": "readonly { events: readonly BaseEvent[]; when: \"initial\" | { toolMessageFor: string } }[]",
586853
"examples": []
587854
},
855+
{
856+
"name": "InterruptSessionPhase",
857+
"kind": "type",
858+
"description": "",
859+
"signature": "\"none\" | \"collecting\" | \"pending\" | \"claimed\" | \"resuming\" | \"acknowledged\" | \"uncertain\" | \"recovery-required\"",
860+
"examples": []
861+
},
862+
{
863+
"name": "InterruptTransport",
864+
"kind": "type",
865+
"description": "",
866+
"signature": "\"auto\" | \"protocol\" | \"legacy-command\" | \"mastra-command\"",
867+
"examples": []
868+
},
588869
{
589870
"name": "bridgeCitationsState",
590871
"kind": "function",
@@ -678,7 +959,7 @@
678959
{
679960
"name": "toAgent",
680961
"kind": "function",
681-
"description": "Wraps an AG-UI AbstractAgent into the runtime-neutral Agent contract.\n\nThe adapter subscribes to source.subscribe({ onEvent }) and reduces every\nevent into the produced Agent's signals. submit() optimistically appends the\nuser message to both our signals and the source agent's internal message\nlist, then calls source.runAgent(). stop() calls source.abortRun().\n\nSubscription cleanup: the returned Agent does NOT manage its own lifetime.\nCallers using DI should rely on the provider's destroy hook; direct callers\nof toAgent() should treat the returned object's lifecycle as tied to the\nagent instance they constructed. The subscriber registered via\nsource.subscribe() will fire for the lifetime of source.",
962+
"description": "Wraps an AG-UI AbstractAgent into the runtime-neutral Agent contract.\n\nThe adapter subscribes to source.subscribe({ onEvent }) and reduces every\nevent into the produced Agent's signals. submit() optimistically appends the\nuser message to both our signals and the source agent's internal message\nlist, then calls source.runAgent(). stop() calls source.abortRun().\n\nSubscription cleanup: providers dispose the adapter with their injector.\nDirect callers must call dispose() when they no longer need the adapter.",
682963
"signature": "toAgent(source: AbstractAgent<>, options: ToAgentOptions): AgUiAgent<>",
683964
"params": [
684965
{

0 commit comments

Comments
 (0)