@parall/parel-channel 1.40.0 → 1.41.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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAK1D;;;;;;;;;;;;;GAaG;AACH,QAAA,MAAM,SAAS,EAAE,gBAMhB,CAAC;AAEF,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAU1D;;;;;;;;;;;;;GAaG;AACH,QAAA,MAAM,SAAS,EAAE,gBAOhB,CAAC;AAEF,eAAe,SAAS,CAAC"}
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { connectParall } from './connect.js';
2
2
  import { buildParallDelivery } from './delivery.js';
3
- import { catchUpParall, handleParallAgentEvent, handleParallFrame } from './inbound.js';
3
+ import { catchUpParall, handleParallAgentEvent, handleParallFrame, handleParallTimer, } from './inbound.js';
4
4
  /**
5
5
  * Parall channel plugin for the parel runtime.
6
6
  *
@@ -19,6 +19,7 @@ const connector = {
19
19
  connect: connectParall,
20
20
  onOpen: catchUpParall,
21
21
  onMessage: handleParallFrame,
22
+ onTimer: handleParallTimer,
22
23
  onAgentEvent: handleParallAgentEvent,
23
24
  deliver: buildParallDelivery,
24
25
  };
@@ -0,0 +1,63 @@
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
@@ -0,0 +1 @@
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"}
@@ -0,0 +1,16 @@
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/dist/session.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ConnectorContext } from '@parel/plugin-sdk';
1
+ import type { ConnectorContext, ConnectorEffect } from '@parel/plugin-sdk';
2
2
  /**
3
3
  * Best-effort progress reporting: dispatch received, AgentSession lifecycle,
4
4
  * and input steps — the signals parall's message-level activity indicator and
@@ -33,6 +33,32 @@ export declare function reportingEnabled(ctx: ConnectorContext): boolean;
33
33
  * simply never read again.)
34
34
  */
35
35
  export declare const TURN_ENVELOPE_KEY = "turnEnvelope:main";
36
+ export declare const SESSION_CACHE_KEY = "session:main";
37
+ /**
38
+ * Conversation key for envelope subjects and fork routing. Thread-aware:
39
+ * parel's turn grouping (F2) and mid-turn injection (F3) key on the envelope
40
+ * subject, and a turn carries ONE reply route — grouping two threads of the
41
+ * same chat under one subject would absorb thread B into thread A's turn and
42
+ * deliver its reply to the wrong thread (agent-core's lane keys draw the
43
+ * same thread/channel line). `~` is outside both nanoid and ULID alphabets,
44
+ * so the composite never collides with a plain id.
45
+ */
46
+ export declare function conversationKey(chatId: string, threadRootId?: string): string;
47
+ /**
48
+ * The addressable entity id inside a (possibly thread-composite) subject.
49
+ * Splits ONLY the `cht_…~msg_…` composite conversationKey produces — typed
50
+ * wiki subjects are scheme-stripped paths where `~` is a legal character
51
+ * (e.g. `wik_1/docs/~draft.md`) and must pass through untouched.
52
+ */
53
+ export declare function subjectEntityId(subject: string): string;
54
+ /**
55
+ * Step broadcast routing by subject shape: chat ids and channel conversations
56
+ * have live subscribers; task/schedule/trigger/wiki subjects are stored-only
57
+ * targets (the server publishes step WS events for chat/task targets and
58
+ * simply persists the rest). Mirrors agent-core's resolveStepTarget so both
59
+ * runtimes' session panels read identically.
60
+ */
61
+ export declare function stepTargetTypeFor(subject: string): string;
36
62
  /**
37
63
  * 'stale' means the session id no longer accepts writes (closed/superseded —
38
64
  * e.g. the New Session control ended it): callers invalidate the cache and
@@ -53,6 +79,26 @@ export declare function invalidateSession(ctx: ConnectorContext): Promise<void>;
53
79
  export declare function ensureSession(ctx: ConnectorContext, opts?: {
54
80
  timeoutMs?: number;
55
81
  }): Promise<string | null>;
82
+ /**
83
+ * Resolve the CURRENT main ase_ from the server, bypassing the cache — the
84
+ * onOpen generation check needs the authoritative id to compare against the
85
+ * cached one (New Session rotates it). Updates the cache on success; returns
86
+ * null on failure WITHOUT touching the cache (the caller must not lose its
87
+ * only generation token to a transient error).
88
+ */
89
+ export declare function fetchMainSessionFresh(ctx: ConnectorContext): Promise<string | null>;
90
+ /**
91
+ * Get-or-create the parall AgentSession mirroring one fork child session
92
+ * (ase_ with parent_session_id → the main ase_, runtime_session_id = the
93
+ * opaque childRef — the connector never sees parel's internal session id).
94
+ * Same caching/degradation posture as ensureSession; the parent resolve
95
+ * reuses the main-session cache so the extra cost is one store read.
96
+ */
97
+ export declare function ensureChildSession(ctx: ConnectorContext, childRef: string, opts?: {
98
+ timeoutMs?: number;
99
+ }): Promise<string | null>;
100
+ /** Drop one child session's cache row (its ase_ was closed under us). */
101
+ export declare function invalidateChildSession(ctx: ConnectorContext, childRef: string): Promise<void>;
56
102
  /** PATCH the session (status / trigger_message_id). Never throws. */
57
103
  export declare function patchSession(ctx: ConnectorContext, sessionId: string, body: {
58
104
  status: 'active' | 'idle';
@@ -87,6 +133,27 @@ export declare function createChannelInputStep(ctx: ConnectorContext, sessionId:
87
133
  text: string;
88
134
  sentAt?: string;
89
135
  }): Promise<ReportResult>;
136
+ /**
137
+ * Input step for a typed (non-message) dispatch — task/schedule/trigger/
138
+ * wiki-comment/approval events. Same processing-ring/panel role as the chat
139
+ * input step; the target routes the record to the source entity instead of a
140
+ * chat (typed dispatches have no message-level indicator, so the step is the
141
+ * panel timeline entry, not an indicator driver).
142
+ */
143
+ export declare function createTypedInputStep(ctx: ConnectorContext, sessionId: string, args: {
144
+ target: {
145
+ type: string;
146
+ id: string;
147
+ } | null;
148
+ triggerType: string;
149
+ /** WorkItem id — the replay identity. source_id is NOT unique per event
150
+ * for task WorkItems (it can be the task id), so keying the step on it
151
+ * would suppress every later event's input step for the same task. */
152
+ dispatchId: string;
153
+ sourceId: string;
154
+ summary: string;
155
+ senderId?: string;
156
+ }): Promise<ReportResult>;
90
157
  /**
91
158
  * Credential redaction for runtime error strings that become user-visible
92
159
  * step content. Two layers: every secret VALUE the connector actually holds
@@ -148,6 +215,26 @@ export declare function createTraceStep(ctx: ConnectorContext, sessionId: string
148
215
  durationMs?: number;
149
216
  outputPreview?: string;
150
217
  }): Promise<ReportResult>;
218
+ /**
219
+ * Ack a dispatch by source so it leaves the pending queue (idempotent).
220
+ * Typed as the fetch effect so it can ride BOTH hook channels (onMessage's
221
+ * ConnectorEffect[] and onAgentEvent's AgentEventEffect[] — the fork spawn
222
+ * ack fires from a child agent event).
223
+ */
224
+ export declare function ackEffect(ctx: ConnectorContext, sourceType: string, sourceId: string): Extract<ConnectorEffect, {
225
+ type: 'fetch';
226
+ }>;
227
+ /**
228
+ * Ack ONE dispatch WorkItem by its id. Typed dispatches must use this form:
229
+ * sibling WorkItems (e.g. a task mutation's task_assign + task_update rows)
230
+ * share (source_type, source_id), so the by-source ack would terminally
231
+ * resolve work that was never emitted. Message dispatches keep the by-source
232
+ * form (one WorkItem per message; the source ack is the established legacy
233
+ * contract).
234
+ */
235
+ export declare function ackByIdEffect(ctx: ConnectorContext, dispatchId: string): Extract<ConnectorEffect, {
236
+ type: 'fetch';
237
+ }>;
151
238
  /**
152
239
  * Lights the pending ring (server broadcasts dispatch.received). Must COMPLETE
153
240
  * before the ack effect is returned: MarkReceived only transitions rows still
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAG3E;;;;;;;;;;;;;;;;GAgBG;AAEH,eAAO,MAAM,kBAAkB,QAAS,CAAC;AAEzC,8EAA8E;AAC9E,eAAO,MAAM,gBAAgB,SAAS,CAAC;AAEvC,8EAA8E;AAC9E,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAE/D;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,sBAAqC,CAAC;AACpE,eAAO,MAAM,iBAAiB,iBAAgC,CAAC;AAG/D;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAE7E;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAMvD;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAOzD;AAED;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,OAAO,GAAG,QAAQ,CAAC;AAMrD,2EAA2E;AAC3E,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAE5E;AASD;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,gBAAgB,EACrB,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAChC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAyBxB;AAED;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAmBzF;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,gBAAgB,EACrB,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAChC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAkCxB;AAED,yEAAyE;AACzE,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,gBAAgB,EACrB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,qEAAqE;AACrE,wBAAsB,YAAY,CAChC,GAAG,EAAE,gBAAgB,EACrB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE;IAAE,MAAM,EAAE,QAAQ,GAAG,MAAM,CAAC;IAAC,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/D,OAAO,CAAC,YAAY,CAAC,CAgBvB;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,gBAAgB,EACrB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC3E,OAAO,CAAC,YAAY,CAAC,CA8BvB;AAED;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,gBAAgB,EACrB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE;IACJ,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GACA,OAAO,CAAC,YAAY,CAAC,CAsCvB;AAED;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACxC,GAAG,EAAE,gBAAgB,EACrB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE;IACJ,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC5C,WAAW,EAAE,MAAM,CAAC;IACpB;;0EAEsE;IACtE,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GACA,OAAO,CAAC,YAAY,CAAC,CA4BvB;AAID;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,GAAE,MAAM,EAAO,GAAG,MAAM,CAY3E;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,gBAAgB,EACrB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACvD,OAAO,CAAC,YAAY,CAAC,CAiCvB;AAOD;;;;;;;;;;;GAWG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,gBAAgB,EACrB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,KAAK,EACD;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC1D;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GACpF;IACE,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,IAAI,GAAG,OAAO,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,GACJ,OAAO,CAAC,YAAY,CAAC,CAmEvB;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,GAAG,EAAE,gBAAgB,EACrB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,eAAe,EAAE;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,CAc7C;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,gBAAgB,EACrB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,eAAe,EAAE;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,CAc7C;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,GAAG,EAAE,gBAAgB,EACrB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAcf"}
package/dist/session.js CHANGED
@@ -35,7 +35,54 @@ export function reportingEnabled(ctx) {
35
35
  * simply never read again.)
36
36
  */
37
37
  export const TURN_ENVELOPE_KEY = `turnEnvelope:${MAIN_SESSION_KEY}`;
38
- const SESSION_CACHE_KEY = `session:${MAIN_SESSION_KEY}`;
38
+ export const SESSION_CACHE_KEY = `session:${MAIN_SESSION_KEY}`;
39
+ const childSessionCacheKey = (childRef) => `sessionChild:${childRef}`;
40
+ /**
41
+ * Conversation key for envelope subjects and fork routing. Thread-aware:
42
+ * parel's turn grouping (F2) and mid-turn injection (F3) key on the envelope
43
+ * subject, and a turn carries ONE reply route — grouping two threads of the
44
+ * same chat under one subject would absorb thread B into thread A's turn and
45
+ * deliver its reply to the wrong thread (agent-core's lane keys draw the
46
+ * same thread/channel line). `~` is outside both nanoid and ULID alphabets,
47
+ * so the composite never collides with a plain id.
48
+ */
49
+ export function conversationKey(chatId, threadRootId) {
50
+ return threadRootId ? `${chatId}~${threadRootId}` : chatId;
51
+ }
52
+ /**
53
+ * The addressable entity id inside a (possibly thread-composite) subject.
54
+ * Splits ONLY the `cht_…~msg_…` composite conversationKey produces — typed
55
+ * wiki subjects are scheme-stripped paths where `~` is a legal character
56
+ * (e.g. `wik_1/docs/~draft.md`) and must pass through untouched.
57
+ */
58
+ export function subjectEntityId(subject) {
59
+ const sep = subject.indexOf('~');
60
+ if (sep === -1)
61
+ return subject;
62
+ const head = subject.slice(0, sep);
63
+ const tail = subject.slice(sep + 1);
64
+ return head.startsWith('cht_') && tail.startsWith('msg_') ? head : subject;
65
+ }
66
+ /**
67
+ * Step broadcast routing by subject shape: chat ids and channel conversations
68
+ * have live subscribers; task/schedule/trigger/wiki subjects are stored-only
69
+ * targets (the server publishes step WS events for chat/task targets and
70
+ * simply persists the rest). Mirrors agent-core's resolveStepTarget so both
71
+ * runtimes' session panels read identically.
72
+ */
73
+ export function stepTargetTypeFor(subject) {
74
+ if (subject.startsWith('chv_'))
75
+ return 'channel_conversation';
76
+ if (subject.startsWith('tsk_'))
77
+ return 'task';
78
+ if (subject.startsWith('sch_'))
79
+ return 'schedule';
80
+ if (subject.startsWith('xtr_'))
81
+ return 'external_trigger';
82
+ if (subject.startsWith('wcs_') || subject.startsWith('wik_'))
83
+ return 'wiki';
84
+ return 'chat';
85
+ }
39
86
  function resultForStatus(status) {
40
87
  return status === 404 || status === 409 || status === 410 ? 'stale' : 'failed';
41
88
  }
@@ -87,6 +134,87 @@ export async function ensureSession(ctx, opts = {}) {
87
134
  return null;
88
135
  }
89
136
  }
137
+ /**
138
+ * Resolve the CURRENT main ase_ from the server, bypassing the cache — the
139
+ * onOpen generation check needs the authoritative id to compare against the
140
+ * cached one (New Session rotates it). Updates the cache on success; returns
141
+ * null on failure WITHOUT touching the cache (the caller must not lose its
142
+ * only generation token to a transient error).
143
+ */
144
+ export async function fetchMainSessionFresh(ctx) {
145
+ if (!reportingEnabled(ctx))
146
+ return null;
147
+ try {
148
+ const url = `${parallApiUrl(ctx)}/api/v1/orgs/${parallOrgId(ctx)}/agents/${parallAgentId(ctx)}/sessions`;
149
+ const res = await fetch(url, {
150
+ method: 'POST',
151
+ headers: jsonHeaders(ctx),
152
+ body: JSON.stringify({ runtime_type: 'parel', runtime_session_id: MAIN_SESSION_KEY }),
153
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
154
+ });
155
+ if (!res.ok)
156
+ return null;
157
+ const body = (await res.json().catch(() => null));
158
+ const id = body?.id;
159
+ if (!id)
160
+ return null;
161
+ await ctx.store?.set(SESSION_CACHE_KEY, id).catch(() => { });
162
+ return id;
163
+ }
164
+ catch {
165
+ return null;
166
+ }
167
+ }
168
+ /**
169
+ * Get-or-create the parall AgentSession mirroring one fork child session
170
+ * (ase_ with parent_session_id → the main ase_, runtime_session_id = the
171
+ * opaque childRef — the connector never sees parel's internal session id).
172
+ * Same caching/degradation posture as ensureSession; the parent resolve
173
+ * reuses the main-session cache so the extra cost is one store read.
174
+ */
175
+ export async function ensureChildSession(ctx, childRef, opts = {}) {
176
+ if (!reportingEnabled(ctx))
177
+ return null;
178
+ const cacheKey = childSessionCacheKey(childRef);
179
+ const cached = await ctx.store?.get(cacheKey).catch(() => null);
180
+ if (typeof cached === 'string' && cached)
181
+ return cached;
182
+ const parentId = await ensureSession(ctx, opts);
183
+ try {
184
+ const url = `${parallApiUrl(ctx)}/api/v1/orgs/${parallOrgId(ctx)}/agents/${parallAgentId(ctx)}/sessions`;
185
+ const res = await fetch(url, {
186
+ method: 'POST',
187
+ headers: jsonHeaders(ctx),
188
+ body: JSON.stringify({
189
+ runtime_type: 'parel',
190
+ runtime_session_id: childRef,
191
+ // Forks sit outside the main-lane uniqueness (parent set), mirroring
192
+ // the standard runtimes' fork ase_ semantics.
193
+ runtime_lane_key: `agent:fork:parel:${childRef}`,
194
+ ...(parentId ? { parent_session_id: parentId } : {}),
195
+ }),
196
+ signal: AbortSignal.timeout(opts.timeoutMs ?? REQUEST_TIMEOUT_MS),
197
+ });
198
+ if (!res.ok) {
199
+ console.error(`[parel-channel] child session get-or-create failed (${res.status})`);
200
+ return null;
201
+ }
202
+ const body = (await res.json().catch(() => null));
203
+ const id = body?.id;
204
+ if (!id)
205
+ return null;
206
+ await ctx.store?.set(cacheKey, id).catch(() => { });
207
+ return id;
208
+ }
209
+ catch (err) {
210
+ console.error('[parel-channel] child session get-or-create failed', err);
211
+ return null;
212
+ }
213
+ }
214
+ /** Drop one child session's cache row (its ase_ was closed under us). */
215
+ export async function invalidateChildSession(ctx, childRef) {
216
+ await ctx.store?.delete(childSessionCacheKey(childRef)).catch(() => { });
217
+ }
90
218
  /** PATCH the session (status / trigger_message_id). Never throws. */
91
219
  export async function patchSession(ctx, sessionId, body) {
92
220
  try {
@@ -194,6 +322,44 @@ export async function createChannelInputStep(ctx, sessionId, args) {
194
322
  return 'failed';
195
323
  }
196
324
  }
325
+ /**
326
+ * Input step for a typed (non-message) dispatch — task/schedule/trigger/
327
+ * wiki-comment/approval events. Same processing-ring/panel role as the chat
328
+ * input step; the target routes the record to the source entity instead of a
329
+ * chat (typed dispatches have no message-level indicator, so the step is the
330
+ * panel timeline entry, not an indicator driver).
331
+ */
332
+ export async function createTypedInputStep(ctx, sessionId, args) {
333
+ try {
334
+ const url = `${parallApiUrl(ctx)}/api/v1/orgs/${parallOrgId(ctx)}/agents/${parallAgentId(ctx)}/sessions/${sessionId}/steps`;
335
+ const res = await fetch(url, {
336
+ method: 'POST',
337
+ headers: jsonHeaders(ctx),
338
+ body: JSON.stringify({
339
+ step_type: 'input',
340
+ ...(args.target ? { target_type: args.target.type, target_id: args.target.id } : {}),
341
+ // Session-scoped dedup — a failed ack leaves the dispatch replayable
342
+ // by the catch-up sweep, same rationale as the chat input step.
343
+ idempotency_key: `input:${args.dispatchId || args.sourceId}`,
344
+ content: {
345
+ trigger_type: args.triggerType,
346
+ trigger_ref: { source_id: args.sourceId },
347
+ ...(args.senderId ? { sender_id: args.senderId } : {}),
348
+ summary: args.summary.slice(0, 200),
349
+ },
350
+ }),
351
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
352
+ });
353
+ if (res.ok)
354
+ return 'ok';
355
+ console.error(`[parel-channel] typed input step failed (${res.status})`);
356
+ return resultForStatus(res.status);
357
+ }
358
+ catch (err) {
359
+ console.error('[parel-channel] typed input step failed', err);
360
+ return 'failed';
361
+ }
362
+ }
197
363
  const ERROR_TEXT_MAX = 500;
198
364
  /**
199
365
  * Credential redaction for runtime error strings that become user-visible
@@ -239,16 +405,18 @@ export async function createErrorStep(ctx, sessionId, args) {
239
405
  const text = `Turn failed: ${redactSecrets(args.error, knownSecrets)}`.slice(0, ERROR_TEXT_MAX);
240
406
  try {
241
407
  const url = `${parallApiUrl(ctx)}/api/v1/orgs/${parallOrgId(ctx)}/agents/${parallAgentId(ctx)}/sessions/${sessionId}/steps`;
242
- // Same subject-prefix line createTraceStep draws: chv_ turns must not
243
- // target 'chat' or the broadcast lands on a channel no client watches.
244
- const targetType = args.subject.startsWith('chv_') ? 'channel_conversation' : 'chat';
408
+ // Same subject-shape line createTraceStep draws: non-chat subjects must
409
+ // not target 'chat' or the broadcast lands on a channel no client
410
+ // watches. Thread-composite subjects address the chat itself.
411
+ const targetId = subjectEntityId(args.subject);
412
+ const targetType = stepTargetTypeFor(targetId);
245
413
  const res = await fetch(url, {
246
414
  method: 'POST',
247
415
  headers: jsonHeaders(ctx),
248
416
  body: JSON.stringify({
249
417
  step_type: 'text',
250
418
  target_type: targetType,
251
- target_id: args.subject,
419
+ target_id: targetId,
252
420
  // At-most-once today (agent-event pushes are not replayed), but the
253
421
  // turnId key makes a future retry path free of duplicate error rows.
254
422
  idempotency_key: `error:${args.turnId}`,
@@ -331,15 +499,17 @@ export async function createTraceStep(ctx, sessionId, subject, event) {
331
499
  }
332
500
  try {
333
501
  const url = `${parallApiUrl(ctx)}/api/v1/orgs/${parallOrgId(ctx)}/agents/${parallAgentId(ctx)}/sessions/${sessionId}/steps`;
334
- // The subject prefix tells chat turns from external IM turns — channel
335
- // steps must not target 'chat' or the server would broadcast them onto
336
- // a messages:{chv_} channel no client subscribes to (agent-core's
337
- // resolveStepTarget draws the same line).
338
- const targetType = subject.startsWith('chv_') ? 'channel_conversation' : 'chat';
502
+ // The subject shape tells chat turns from external IM / typed-entity
503
+ // turns — non-chat steps must not target 'chat' or the server would
504
+ // broadcast them onto a messages:{…} channel no client subscribes to
505
+ // (agent-core's resolveStepTarget draws the same line). Thread-composite
506
+ // subjects address the chat itself.
507
+ const targetId = subjectEntityId(subject);
508
+ const targetType = stepTargetTypeFor(targetId);
339
509
  const res = await fetch(url, {
340
510
  method: 'POST',
341
511
  headers: jsonHeaders(ctx),
342
- body: JSON.stringify({ ...body, target_type: targetType, target_id: subject }),
512
+ body: JSON.stringify({ ...body, target_type: targetType, target_id: targetId }),
343
513
  signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
344
514
  });
345
515
  if (res.ok)
@@ -352,6 +522,50 @@ export async function createTraceStep(ctx, sessionId, subject, event) {
352
522
  return 'failed';
353
523
  }
354
524
  }
525
+ /**
526
+ * Ack a dispatch by source so it leaves the pending queue (idempotent).
527
+ * Typed as the fetch effect so it can ride BOTH hook channels (onMessage's
528
+ * ConnectorEffect[] and onAgentEvent's AgentEventEffect[] — the fork spawn
529
+ * ack fires from a child agent event).
530
+ */
531
+ export function ackEffect(ctx, sourceType, sourceId) {
532
+ return {
533
+ type: 'fetch',
534
+ request: {
535
+ url: `${parallApiUrl(ctx)}/api/v1/orgs/${parallOrgId(ctx)}/dispatch/ack`,
536
+ method: 'POST',
537
+ headers: {
538
+ Authorization: `Bearer ${requireAgk(ctx)}`,
539
+ 'Content-Type': 'application/json',
540
+ },
541
+ body: JSON.stringify({ source_type: sourceType, source_id: sourceId }),
542
+ },
543
+ idempotencyKey: `ack:${sourceType}:${sourceId}`,
544
+ };
545
+ }
546
+ /**
547
+ * Ack ONE dispatch WorkItem by its id. Typed dispatches must use this form:
548
+ * sibling WorkItems (e.g. a task mutation's task_assign + task_update rows)
549
+ * share (source_type, source_id), so the by-source ack would terminally
550
+ * resolve work that was never emitted. Message dispatches keep the by-source
551
+ * form (one WorkItem per message; the source ack is the established legacy
552
+ * contract).
553
+ */
554
+ export function ackByIdEffect(ctx, dispatchId) {
555
+ return {
556
+ type: 'fetch',
557
+ request: {
558
+ url: `${parallApiUrl(ctx)}/api/v1/orgs/${parallOrgId(ctx)}/dispatch/${dispatchId}/ack`,
559
+ method: 'POST',
560
+ headers: {
561
+ Authorization: `Bearer ${requireAgk(ctx)}`,
562
+ 'Content-Type': 'application/json',
563
+ },
564
+ body: '{}',
565
+ },
566
+ idempotencyKey: `ackid:${dispatchId}`,
567
+ };
568
+ }
355
569
  /**
356
570
  * Lights the pending ring (server broadcasts dispatch.received). Must COMPLETE
357
571
  * before the ack effect is returned: MarkReceived only transitions rows still
@@ -0,0 +1,76 @@
1
+ import type { ConnectorContext } from '@parel/plugin-sdk';
2
+ /**
3
+ * Typed (non-message) dispatches → agent events.
4
+ *
5
+ * Mirrors the standard runtimes' coverage (agent-core gateway dispatch.new
6
+ * switch; hermes adapter's inline port): task_assign / task_update /
7
+ * task_comment / wiki_comment / schedule.fire / external_trigger /
8
+ * approval_decided. Each handler pulls the source entity, renders the same
9
+ * event-body line format agent-core's buildEventBody produces (so an agent
10
+ * moved between runtimes reads identical events), and returns a plan the
11
+ * inbound pipeline turns into envelope + progress reporting + ack.
12
+ *
13
+ * Semantics carried over from the standard runtimes:
14
+ * - Permanently-unusable sources (404/403, deleted comments, no_reply hints,
15
+ * stale task assignment) resolve to `stale` — the caller acks and drops.
16
+ * - Transient fetch failures resolve to `pending` — the dispatch stays
17
+ * pending and the reconnect catch-up sweep retries it.
18
+ * - schedule.fire tolerates 404 by contract (post-fire PATCH on target_ids /
19
+ * attached_to_uri legitimately revokes access to a delivered run snapshot;
20
+ * docs/primitives/schedule.md § Snapshot 不变性) — warn + ack + drop.
21
+ *
22
+ * Reply semantics differ from chat messages ON PURPOSE: a typed turn's
23
+ * turn-end text has no chat to deliver to (deliver() only runs the redundant
24
+ * idle), and the agent acts through its sandbox CLI instead — identical to
25
+ * the standard runtimes, where typed events are answered with CLI actions,
26
+ * not auto-delivered text. approval_decided is the one exception: it lives
27
+ * in a chat, so its plan carries the chatId and the reply auto-delivers
28
+ * there like any chat message.
29
+ */
30
+ export interface TypedDispatchData {
31
+ id?: unknown;
32
+ event_type?: unknown;
33
+ source_type?: unknown;
34
+ source_id?: unknown;
35
+ chat_id?: unknown;
36
+ task_id?: unknown;
37
+ actor_id?: unknown;
38
+ delivery_reason?: unknown;
39
+ }
40
+ /** Dispatch event types this module consumes (everything but the message pair). */
41
+ export declare const TYPED_EVENT_TYPES: readonly ["task_assign", "task_update", "task_comment", "wiki_comment", "schedule.fire", "external_trigger", "approval_decided"];
42
+ export declare function isTypedEventType(eventType: string): boolean;
43
+ /** What the inbound pipeline needs to emit + report one typed event. */
44
+ export interface TypedEventPlan {
45
+ outcome: 'emit';
46
+ /** F2 grouping key + agent-event correlation anchor (task/schedule/… id). */
47
+ subject: string;
48
+ /** Framed event body (the envelope's data.text). */
49
+ body: string;
50
+ /** Input-step routing; null skips the step (no meaningful target). */
51
+ stepTarget: {
52
+ type: string;
53
+ id: string;
54
+ } | null;
55
+ /** Input-step content bits. */
56
+ triggerType: string;
57
+ summary: string;
58
+ /** Set only for approval_decided: the reply auto-delivers to this chat. */
59
+ chatId?: string;
60
+ }
61
+ export type TypedDispatchResult = TypedEventPlan
62
+ /** Permanently unusable — ack and drop. */
63
+ | {
64
+ outcome: 'stale';
65
+ }
66
+ /** Transient failure — leave pending for the catch-up sweep. */
67
+ | {
68
+ outcome: 'pending';
69
+ };
70
+ /**
71
+ * Build the plan for one typed dispatch. Never throws: any unexpected error
72
+ * degrades to `pending` (same posture as the message path — the sweep
73
+ * retries, and a poisoned row eventually surfaces as a stuck pending count).
74
+ */
75
+ export declare function planTypedDispatch(data: TypedDispatchData, ctx: ConnectorContext): Promise<TypedDispatchResult>;
76
+ //# sourceMappingURL=typed-dispatch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typed-dispatch.d.ts","sourceRoot":"","sources":["../src/typed-dispatch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAI1D;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,MAAM,WAAW,iBAAiB;IAChC,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,mFAAmF;AACnF,eAAO,MAAM,iBAAiB,kIAQpB,CAAC;AAEX,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED,wEAAwE;AACxE,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,6EAA6E;IAC7E,OAAO,EAAE,MAAM,CAAC;IAChB,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,UAAU,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAChD,+BAA+B;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,mBAAmB,GAC3B,cAAc;AAChB,2CAA2C;GACzC;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE;AACtB,gEAAgE;GAC9D;IAAE,OAAO,EAAE,SAAS,CAAA;CAAE,CAAC;AAY3B;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,iBAAiB,EACvB,GAAG,EAAE,gBAAgB,GACpB,OAAO,CAAC,mBAAmB,CAAC,CAwC9B"}