@parall/parel-channel 1.42.1 → 1.44.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/dist/channel-capability.d.ts +29 -0
- package/dist/channel-capability.d.ts.map +1 -0
- package/dist/channel-capability.js +81 -0
- package/dist/channel-prompt.d.ts +16 -9
- package/dist/channel-prompt.d.ts.map +1 -1
- package/dist/channel-prompt.js +25 -19
- package/dist/delivery.js +1 -1
- package/dist/fork.d.ts +8 -4
- package/dist/fork.d.ts.map +1 -1
- package/dist/inbound-channel.d.ts.map +1 -1
- package/dist/inbound-channel.js +19 -14
- package/dist/inbound.d.ts.map +1 -1
- package/dist/inbound.js +65 -43
- package/dist/session.d.ts +43 -19
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +75 -36
- package/package.json +2 -2
- package/src/channel-capability.ts +121 -0
- package/src/channel-prompt.ts +33 -20
- package/src/delivery.ts +1 -1
- package/src/fork.ts +6 -7
- package/src/inbound-channel.ts +21 -15
- package/src/inbound.ts +75 -52
- package/src/session.ts +81 -34
- package/dist/parel-sdk-compat.d.ts +0 -63
- package/dist/parel-sdk-compat.d.ts.map +0 -1
- package/dist/parel-sdk-compat.js +0 -16
- package/src/parel-sdk-compat.ts +0 -77
package/src/session.ts
CHANGED
|
@@ -590,12 +590,14 @@ export async function createTraceStep(
|
|
|
590
590
|
}
|
|
591
591
|
|
|
592
592
|
/**
|
|
593
|
-
*
|
|
594
|
-
*
|
|
595
|
-
*
|
|
596
|
-
*
|
|
593
|
+
* Terminally drop ONE source's live WorkItem via the unified complete's
|
|
594
|
+
* source form (no covering reply Effect exists for a dropped row, so the
|
|
595
|
+
* server sweeps it to no_action — the drop semantics; idempotent). Typed as
|
|
596
|
+
* the fetch effect so it can ride BOTH hook channels (ConnectorEffect[] and
|
|
597
|
+
* AgentEventEffect[]). Replaces the legacy by-source ack for drop cases —
|
|
598
|
+
* that endpoint retires at S3 (dispatch-convergence-design.md §3).
|
|
597
599
|
*/
|
|
598
|
-
export function
|
|
600
|
+
export function completeSourceEffect(
|
|
599
601
|
ctx: ConnectorContext,
|
|
600
602
|
sourceType: string,
|
|
601
603
|
sourceId: string,
|
|
@@ -603,15 +605,15 @@ export function ackEffect(
|
|
|
603
605
|
return {
|
|
604
606
|
type: 'fetch',
|
|
605
607
|
request: {
|
|
606
|
-
url: `${parallApiUrl(ctx)}/api/v1/orgs/${parallOrgId(ctx)}/dispatch/
|
|
608
|
+
url: `${parallApiUrl(ctx)}/api/v1/orgs/${parallOrgId(ctx)}/dispatch/complete`,
|
|
607
609
|
method: 'POST',
|
|
608
610
|
headers: {
|
|
609
611
|
Authorization: `Bearer ${requireAgk(ctx)}`,
|
|
610
612
|
'Content-Type': 'application/json',
|
|
611
613
|
},
|
|
612
|
-
body: JSON.stringify({ source_type: sourceType, source_id: sourceId }),
|
|
614
|
+
body: JSON.stringify({ sources: [{ source_type: sourceType, source_id: sourceId }] }),
|
|
613
615
|
},
|
|
614
|
-
idempotencyKey: `
|
|
616
|
+
idempotencyKey: `complete:src:${sourceType}:${sourceId}`,
|
|
615
617
|
};
|
|
616
618
|
}
|
|
617
619
|
|
|
@@ -643,31 +645,35 @@ export function ackByIdEffect(
|
|
|
643
645
|
}
|
|
644
646
|
|
|
645
647
|
/**
|
|
646
|
-
*
|
|
647
|
-
*
|
|
648
|
-
*
|
|
649
|
-
*
|
|
648
|
+
* Claim the source's WorkItem before the turn (server folds the row into its
|
|
649
|
+
* message lane, flips it pending→received and broadcasts dispatch.received —
|
|
650
|
+
* the pending ring rides the claim side effect now; the retired received
|
|
651
|
+
* endpoint was a bare receipt). Best-effort like the receipt was: a refused
|
|
652
|
+
* or failed claim never blocks the emit — the row stays pending and the
|
|
653
|
+
* turn's complete resolves it just the same. Must COMPLETE before any
|
|
654
|
+
* settling effect is returned so a same-batch complete can't race the
|
|
655
|
+
* pending→received transition.
|
|
650
656
|
*/
|
|
651
|
-
export async function
|
|
657
|
+
export async function claimDispatchSource(
|
|
652
658
|
ctx: ConnectorContext,
|
|
653
659
|
sourceType: string,
|
|
654
660
|
sourceId: string,
|
|
655
661
|
): Promise<void> {
|
|
656
662
|
// Deliberately NOT gated on reportingEnabled: this is ledger surface, not
|
|
657
|
-
// session reporting — the URL needs no agent id, and
|
|
658
|
-
//
|
|
659
|
-
//
|
|
663
|
+
// session reporting — the URL needs no agent id, and the claim transition
|
|
664
|
+
// is what keeps the indicator lifecycle working even for agent-id-less old
|
|
665
|
+
// configs.
|
|
660
666
|
try {
|
|
661
|
-
const url = `${parallApiUrl(ctx)}/api/v1/orgs/${parallOrgId(ctx)}/dispatch/
|
|
667
|
+
const url = `${parallApiUrl(ctx)}/api/v1/orgs/${parallOrgId(ctx)}/dispatch/claim`;
|
|
662
668
|
const res = await fetch(url, {
|
|
663
669
|
method: 'POST',
|
|
664
670
|
headers: jsonHeaders(ctx),
|
|
665
671
|
body: JSON.stringify({ source_type: sourceType, source_id: sourceId }),
|
|
666
672
|
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
667
673
|
});
|
|
668
|
-
if (!res.ok) console.error(`[parel-channel]
|
|
674
|
+
if (!res.ok) console.error(`[parel-channel] claim source failed (${res.status})`);
|
|
669
675
|
} catch (err) {
|
|
670
|
-
console.error('[parel-channel]
|
|
676
|
+
console.error('[parel-channel] claim source failed', err);
|
|
671
677
|
}
|
|
672
678
|
}
|
|
673
679
|
|
|
@@ -735,6 +741,25 @@ export async function clearActiveEmit(
|
|
|
735
741
|
await ctx.store?.delete(activeEmitKey(sourceType, sourceId)).catch(() => {});
|
|
736
742
|
}
|
|
737
743
|
|
|
744
|
+
/**
|
|
745
|
+
* Burn the fence after an ERROR close: keep the attempt id (so the re-driven
|
|
746
|
+
* emit's nextEnvelopeId picks a fresh `#r{n+1}` — a bare repeat of the base
|
|
747
|
+
* id could be deduped by parel and strand the retry) but zero the timestamp
|
|
748
|
+
* (so the redelivery-skip window is already over and the server's re-drive
|
|
749
|
+
* hint re-emits immediately instead of hiding behind a 30-min TTL).
|
|
750
|
+
*/
|
|
751
|
+
export async function burnActiveEmit(
|
|
752
|
+
ctx: ConnectorContext,
|
|
753
|
+
sourceType: string,
|
|
754
|
+
sourceId: string,
|
|
755
|
+
): Promise<void> {
|
|
756
|
+
const prior = await readActiveEmit(ctx, sourceType, sourceId);
|
|
757
|
+
if (!prior) return;
|
|
758
|
+
await ctx.store
|
|
759
|
+
?.set(activeEmitKey(sourceType, sourceId), { id: prior.id, at: 0 })
|
|
760
|
+
.catch(() => {});
|
|
761
|
+
}
|
|
762
|
+
|
|
738
763
|
/**
|
|
739
764
|
* Deterministic envelope id for a source: `{sourceType}:{sourceId}` on the
|
|
740
765
|
* first attempt, `…#r{n}` on re-emits. Attempt-suffixed ids are unique per
|
|
@@ -763,6 +788,9 @@ export function sourceFromEnvelopeId(
|
|
|
763
788
|
return { sourceType: bare.slice(0, i), sourceId: bare.slice(i + 1) };
|
|
764
789
|
}
|
|
765
790
|
|
|
791
|
+
/** Turn outcome for the ledger close — mirrors the server's turn_outcome. */
|
|
792
|
+
export type TurnOutcome = 'ok' | 'error';
|
|
793
|
+
|
|
766
794
|
/**
|
|
767
795
|
* Fence-checked turn-end ledger close for a set of envelope ids — the shared
|
|
768
796
|
* core of BOTH turn-end hooks: onAgentEvent (turn_completed/turn_failed, the
|
|
@@ -770,51 +798,70 @@ export function sourceFromEnvelopeId(
|
|
|
770
798
|
* never arrive and this is the ONLY terminal ledger hook — without it a
|
|
771
799
|
* received row would re-emit on every TTL sweep forever). Only sources whose
|
|
772
800
|
* `active:{source}` store row matches the envelope id EXACTLY are completed
|
|
773
|
-
* (attempt fence)
|
|
774
|
-
*
|
|
801
|
+
* (attempt fence). Both hooks running is harmless: whichever completes first
|
|
802
|
+
* consumes the fence, the other skips.
|
|
803
|
+
*
|
|
804
|
+
* Fence disposal follows the outcome: an "ok" close clears the fences (the
|
|
805
|
+
* sources are terminal); an "error" close BURNS them instead — the server
|
|
806
|
+
* released the uncovered members back to pending and its re-drive hint
|
|
807
|
+
* re-emits them, so the burned fence must neither hide the retry behind the
|
|
808
|
+
* redelivery-skip TTL nor let it reuse a dedupe-prone envelope id.
|
|
775
809
|
*/
|
|
776
810
|
export async function completeFencedEnvelopes(
|
|
777
811
|
ctx: ConnectorContext,
|
|
778
812
|
envelopeIds: string[],
|
|
813
|
+
outcome: TurnOutcome = 'ok',
|
|
779
814
|
): Promise<void> {
|
|
780
815
|
const fenced: { source_type: string; source_id: string }[] = [];
|
|
781
816
|
for (const envId of envelopeIds) {
|
|
782
817
|
const src = sourceFromEnvelopeId(envId);
|
|
783
818
|
if (!src) continue; // pre-alignment envelope id (dsp_*) — old rows were acked on emit
|
|
784
819
|
const active = await readActiveEmit(ctx, src.sourceType, src.sourceId);
|
|
785
|
-
|
|
820
|
+
// A BURNED fence (at === 0) still carries the attempt id but the attempt
|
|
821
|
+
// is already error-closed — its members are back in pending awaiting the
|
|
822
|
+
// re-drive. The redundant deliver()-side close for the same envelope
|
|
823
|
+
// must skip here, or its "ok" would no_action-sweep the very rows the
|
|
824
|
+
// error close just released (the retry hole S3a closes).
|
|
825
|
+
if (active?.id === envId && active.at > 0) {
|
|
786
826
|
fenced.push({ source_type: src.sourceType, source_id: src.sourceId });
|
|
787
827
|
}
|
|
788
828
|
}
|
|
789
|
-
if (fenced.length > 0 && (await completeSources(ctx, fenced))) {
|
|
829
|
+
if (fenced.length > 0 && (await completeSources(ctx, fenced, outcome))) {
|
|
790
830
|
for (const src of fenced) {
|
|
791
|
-
|
|
831
|
+
if (outcome === 'error') {
|
|
832
|
+
await burnActiveEmit(ctx, src.source_type, src.source_id);
|
|
833
|
+
} else {
|
|
834
|
+
await clearActiveEmit(ctx, src.source_type, src.source_id);
|
|
835
|
+
}
|
|
792
836
|
}
|
|
793
837
|
}
|
|
794
838
|
}
|
|
795
839
|
|
|
796
840
|
/**
|
|
797
|
-
* Turn-end ledger close: resolves the turn's folded sources on the server
|
|
798
|
-
*
|
|
799
|
-
*
|
|
800
|
-
*
|
|
801
|
-
*
|
|
841
|
+
* Turn-end ledger close: resolves the turn's folded sources on the server via
|
|
842
|
+
* the unified complete's source form (POST /dispatch/complete, idempotent) —
|
|
843
|
+
* broad-cover to the turn's reply Effect when one exists; otherwise a
|
|
844
|
+
* no_action sweep on "ok", or a release back to pending on the redrive budget
|
|
845
|
+
* on "error" (a failed turn must not silently consume work it never handled).
|
|
846
|
+
* One immediate retry on failure; a still-failed call leaves the rows live
|
|
847
|
+
* and the catch-up TTL re-emit self-heals.
|
|
802
848
|
*/
|
|
803
849
|
export async function completeSources(
|
|
804
850
|
ctx: ConnectorContext,
|
|
805
851
|
sources: { source_type: string; source_id: string }[],
|
|
852
|
+
outcome: TurnOutcome = 'ok',
|
|
806
853
|
): Promise<boolean> {
|
|
807
|
-
// Ledger surface — not gated on reportingEnabled (see
|
|
854
|
+
// Ledger surface — not gated on reportingEnabled (see claimDispatchSource).
|
|
808
855
|
if (sources.length === 0) return true;
|
|
809
|
-
const url = `${parallApiUrl(ctx)}/api/v1/orgs/${parallOrgId(ctx)}/dispatch/complete
|
|
856
|
+
const url = `${parallApiUrl(ctx)}/api/v1/orgs/${parallOrgId(ctx)}/dispatch/complete`;
|
|
810
857
|
const attempt = async (): Promise<boolean> => {
|
|
811
858
|
const res = await fetch(url, {
|
|
812
859
|
method: 'POST',
|
|
813
860
|
headers: jsonHeaders(ctx),
|
|
814
|
-
body: JSON.stringify({ sources }),
|
|
861
|
+
body: JSON.stringify({ sources, turn_outcome: outcome }),
|
|
815
862
|
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
816
863
|
});
|
|
817
|
-
if (!res.ok) console.error(`[parel-channel] complete
|
|
864
|
+
if (!res.ok) console.error(`[parel-channel] complete (sources) failed (${res.status})`);
|
|
818
865
|
return res.ok;
|
|
819
866
|
};
|
|
820
867
|
try {
|
|
@@ -825,7 +872,7 @@ export async function completeSources(
|
|
|
825
872
|
try {
|
|
826
873
|
return await attempt();
|
|
827
874
|
} catch (err) {
|
|
828
|
-
console.error('[parel-channel] complete
|
|
875
|
+
console.error('[parel-channel] complete (sources) failed', err);
|
|
829
876
|
return false;
|
|
830
877
|
}
|
|
831
878
|
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import type { AgentEvent, ChannelEnvelope, ConnectorEffect } from '@parel/plugin-sdk';
|
|
2
|
-
/**
|
|
3
|
-
* Local mirrors of parel host types that shipped in parel-mono #140 (F3
|
|
4
|
-
* injectInFlight / F4 child sessions) but are not yet published in
|
|
5
|
-
* @parel/plugin-sdk (the mirror lives on parel-oss branch
|
|
6
|
-
* feat/channel-child-sessions). The host accepts these shapes today — prod
|
|
7
|
-
* runs #140 — so the connector uses them through this compat layer and casts
|
|
8
|
-
* at the hook boundary.
|
|
9
|
-
*
|
|
10
|
-
* TODO(parel-sdk-#140-types): DELETE this file (and the casts) once
|
|
11
|
-
* @parel/plugin-sdk ships the mirror sitting on parel-oss branch
|
|
12
|
-
* `feat/channel-child-sessions` — check the branch/`@parel/plugin-sdk`
|
|
13
|
-
* changelog on every sdk version bump. Until then the shapes below must stay
|
|
14
|
-
* byte-compatible with parel-mono ts/packages/cloudflare/src/channel-types.ts.
|
|
15
|
-
*/
|
|
16
|
-
/**
|
|
17
|
-
* Spawn a fork child session off this connection's main conversation session.
|
|
18
|
-
* Idempotent on childRef (opaque, connector-owned). Host gates: binding must
|
|
19
|
-
* opt in (childSessions) + `main` routing; failures come back asynchronously
|
|
20
|
-
* as a `child_spawn_failed` agent event. The child seeds from the parent
|
|
21
|
-
* transcript at the last turn boundary (never sees in-flight output).
|
|
22
|
-
*/
|
|
23
|
-
export interface SpawnChildSessionEffect {
|
|
24
|
-
type: 'spawnChildSession';
|
|
25
|
-
childRef: string;
|
|
26
|
-
input: string;
|
|
27
|
-
subject?: string;
|
|
28
|
-
}
|
|
29
|
-
/** emitEvent with the #140 deliverTo extension: route to a spawned child. */
|
|
30
|
-
export interface EmitToChildEffect {
|
|
31
|
-
type: 'emitEvent';
|
|
32
|
-
event: ChannelEnvelope;
|
|
33
|
-
deliverTo: {
|
|
34
|
-
childRef: string;
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Asynchronous error channel for a failed spawnChildSession effect (pushed
|
|
39
|
-
* regardless of observe scopes). codes: disabled | unsupported_routing |
|
|
40
|
-
* no_binding | invalid_request | depth_limit | concurrency_limit |
|
|
41
|
-
* spawn_failed.
|
|
42
|
-
*/
|
|
43
|
-
export interface ChildSpawnFailedEvent {
|
|
44
|
-
type: 'child_spawn_failed';
|
|
45
|
-
childRef: string;
|
|
46
|
-
code: string;
|
|
47
|
-
error: string;
|
|
48
|
-
}
|
|
49
|
-
/** Effect union the #140 host actually executes. */
|
|
50
|
-
export type ExtendedConnectorEffect = ConnectorEffect | SpawnChildSessionEffect | EmitToChildEffect;
|
|
51
|
-
/**
|
|
52
|
-
* Every event from a connector-spawned child carries the childRef it was
|
|
53
|
-
* spawned with (#140: AgentEventBase.childRef). Absent on main-session
|
|
54
|
-
* events and on sdk versions that predate the field.
|
|
55
|
-
*/
|
|
56
|
-
export type AgentEventWithChild = AgentEvent & {
|
|
57
|
-
childRef?: string;
|
|
58
|
-
};
|
|
59
|
-
/** Narrow an incoming agent event to the not-yet-published failure shape. */
|
|
60
|
-
export declare function asChildSpawnFailed(event: unknown): ChildSpawnFailedEvent | null;
|
|
61
|
-
/** Cast helper: the host executes the extended union; the sdk type lags it. */
|
|
62
|
-
export declare function asConnectorEffects(effects: ExtendedConnectorEffect[]): ConnectorEffect[];
|
|
63
|
-
//# sourceMappingURL=parel-sdk-compat.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"parel-sdk-compat.d.ts","sourceRoot":"","sources":["../src/parel-sdk-compat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEtF;;;;;;;;;;;;;GAaG;AAEH;;;;;;GAMG;AACH,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,mBAAmB,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,6EAA6E;AAC7E,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,WAAW,CAAC;IAClB,KAAK,EAAE,eAAe,CAAC;IACvB,SAAS,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;CACjC;AAED;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,oBAAoB,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,oDAAoD;AACpD,MAAM,MAAM,uBAAuB,GAAG,eAAe,GAAG,uBAAuB,GAAG,iBAAiB,CAAC;AAEpG;;;;GAIG;AACH,MAAM,MAAM,mBAAmB,GAAG,UAAU,GAAG;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAErE,6EAA6E;AAC7E,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,qBAAqB,GAAG,IAAI,CAS/E;AAED,+EAA+E;AAC/E,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,uBAAuB,EAAE,GAAG,eAAe,EAAE,CAExF"}
|
package/dist/parel-sdk-compat.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/** Narrow an incoming agent event to the not-yet-published failure shape. */
|
|
2
|
-
export function asChildSpawnFailed(event) {
|
|
3
|
-
const e = event;
|
|
4
|
-
if (e?.type !== 'child_spawn_failed')
|
|
5
|
-
return null;
|
|
6
|
-
return {
|
|
7
|
-
type: 'child_spawn_failed',
|
|
8
|
-
childRef: typeof e.childRef === 'string' ? e.childRef : '',
|
|
9
|
-
code: typeof e.code === 'string' ? e.code : 'unknown',
|
|
10
|
-
error: typeof e.error === 'string' ? e.error : '',
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
/** Cast helper: the host executes the extended union; the sdk type lags it. */
|
|
14
|
-
export function asConnectorEffects(effects) {
|
|
15
|
-
return effects;
|
|
16
|
-
}
|
package/src/parel-sdk-compat.ts
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import type { AgentEvent, ChannelEnvelope, ConnectorEffect } from '@parel/plugin-sdk';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Local mirrors of parel host types that shipped in parel-mono #140 (F3
|
|
5
|
-
* injectInFlight / F4 child sessions) but are not yet published in
|
|
6
|
-
* @parel/plugin-sdk (the mirror lives on parel-oss branch
|
|
7
|
-
* feat/channel-child-sessions). The host accepts these shapes today — prod
|
|
8
|
-
* runs #140 — so the connector uses them through this compat layer and casts
|
|
9
|
-
* at the hook boundary.
|
|
10
|
-
*
|
|
11
|
-
* TODO(parel-sdk-#140-types): DELETE this file (and the casts) once
|
|
12
|
-
* @parel/plugin-sdk ships the mirror sitting on parel-oss branch
|
|
13
|
-
* `feat/channel-child-sessions` — check the branch/`@parel/plugin-sdk`
|
|
14
|
-
* changelog on every sdk version bump. Until then the shapes below must stay
|
|
15
|
-
* byte-compatible with parel-mono ts/packages/cloudflare/src/channel-types.ts.
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Spawn a fork child session off this connection's main conversation session.
|
|
20
|
-
* Idempotent on childRef (opaque, connector-owned). Host gates: binding must
|
|
21
|
-
* opt in (childSessions) + `main` routing; failures come back asynchronously
|
|
22
|
-
* as a `child_spawn_failed` agent event. The child seeds from the parent
|
|
23
|
-
* transcript at the last turn boundary (never sees in-flight output).
|
|
24
|
-
*/
|
|
25
|
-
export interface SpawnChildSessionEffect {
|
|
26
|
-
type: 'spawnChildSession';
|
|
27
|
-
childRef: string;
|
|
28
|
-
input: string;
|
|
29
|
-
subject?: string;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/** emitEvent with the #140 deliverTo extension: route to a spawned child. */
|
|
33
|
-
export interface EmitToChildEffect {
|
|
34
|
-
type: 'emitEvent';
|
|
35
|
-
event: ChannelEnvelope;
|
|
36
|
-
deliverTo: { childRef: string };
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Asynchronous error channel for a failed spawnChildSession effect (pushed
|
|
41
|
-
* regardless of observe scopes). codes: disabled | unsupported_routing |
|
|
42
|
-
* no_binding | invalid_request | depth_limit | concurrency_limit |
|
|
43
|
-
* spawn_failed.
|
|
44
|
-
*/
|
|
45
|
-
export interface ChildSpawnFailedEvent {
|
|
46
|
-
type: 'child_spawn_failed';
|
|
47
|
-
childRef: string;
|
|
48
|
-
code: string;
|
|
49
|
-
error: string;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/** Effect union the #140 host actually executes. */
|
|
53
|
-
export type ExtendedConnectorEffect = ConnectorEffect | SpawnChildSessionEffect | EmitToChildEffect;
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Every event from a connector-spawned child carries the childRef it was
|
|
57
|
-
* spawned with (#140: AgentEventBase.childRef). Absent on main-session
|
|
58
|
-
* events and on sdk versions that predate the field.
|
|
59
|
-
*/
|
|
60
|
-
export type AgentEventWithChild = AgentEvent & { childRef?: string };
|
|
61
|
-
|
|
62
|
-
/** Narrow an incoming agent event to the not-yet-published failure shape. */
|
|
63
|
-
export function asChildSpawnFailed(event: unknown): ChildSpawnFailedEvent | null {
|
|
64
|
-
const e = event as { type?: unknown; childRef?: unknown; code?: unknown; error?: unknown };
|
|
65
|
-
if (e?.type !== 'child_spawn_failed') return null;
|
|
66
|
-
return {
|
|
67
|
-
type: 'child_spawn_failed',
|
|
68
|
-
childRef: typeof e.childRef === 'string' ? e.childRef : '',
|
|
69
|
-
code: typeof e.code === 'string' ? e.code : 'unknown',
|
|
70
|
-
error: typeof e.error === 'string' ? e.error : '',
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/** Cast helper: the host executes the extended union; the sdk type lags it. */
|
|
75
|
-
export function asConnectorEffects(effects: ExtendedConnectorEffect[]): ConnectorEffect[] {
|
|
76
|
-
return effects as ConnectorEffect[];
|
|
77
|
-
}
|