@parall/parel-channel 1.52.0 → 1.52.2
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-prompt.d.ts +2 -0
- package/dist/channel-prompt.d.ts.map +1 -1
- package/dist/channel-prompt.js +2 -0
- package/dist/delivery.d.ts.map +1 -1
- package/dist/delivery.js +12 -6
- package/dist/fork.d.ts +11 -7
- package/dist/fork.d.ts.map +1 -1
- package/dist/fork.js +11 -7
- package/dist/inbound.d.ts.map +1 -1
- package/dist/inbound.js +47 -18
- package/dist/session.d.ts +17 -0
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +43 -0
- package/package.json +1 -1
- package/src/channel-prompt.ts +3 -0
- package/src/delivery.ts +12 -5
- package/src/fork.ts +11 -7
- package/src/inbound.ts +61 -17
- package/src/session.ts +44 -0
package/dist/channel-prompt.d.ts
CHANGED
|
@@ -43,6 +43,8 @@ export interface ChatPromptArgs {
|
|
|
43
43
|
text: string;
|
|
44
44
|
/** Message attachments — rendered as reference lines (agent fetches via CLI). */
|
|
45
45
|
attachments?: PromptAttachment[];
|
|
46
|
+
/** message.hints.no_reply — rendered as the same [Hint: no_reply] line agent-core injects. */
|
|
47
|
+
noReply?: boolean;
|
|
46
48
|
}
|
|
47
49
|
/**
|
|
48
50
|
* Frame a Parall chat message with its conversation of origin. Kept to a
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channel-prompt.d.ts","sourceRoot":"","sources":["../src/channel-prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AASH,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAC;IACb,iFAAiF;IACjF,WAAW,CAAC,EAAE,gBAAgB,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"channel-prompt.d.ts","sourceRoot":"","sources":["../src/channel-prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AASH,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAC;IACb,iFAAiF;IACjF,WAAW,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACjC,8FAA8F;IAC9F,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAmBD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAW5D;AAED,MAAM,WAAW,iBAAiB;IAChC,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;IACb;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAkBlE"}
|
package/dist/channel-prompt.js
CHANGED
|
@@ -63,6 +63,8 @@ export function buildChatPrompt(args) {
|
|
|
63
63
|
lines.push(`[From: ${sanitizeMeta(args.senderId)}]`);
|
|
64
64
|
if (args.threadRootId)
|
|
65
65
|
lines.push(`[Thread: ${sanitizeMeta(args.threadRootId)}]`);
|
|
66
|
+
if (args.noReply)
|
|
67
|
+
lines.push(`[Hint: no_reply]`);
|
|
66
68
|
lines.push(...attachmentLines(args.attachments));
|
|
67
69
|
lines.push('', args.text);
|
|
68
70
|
return lines.join('\n');
|
package/dist/delivery.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delivery.d.ts","sourceRoot":"","sources":["../src/delivery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"delivery.d.ts","sourceRoot":"","sources":["../src/delivery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAc5F;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,eAAe,EACzB,GAAG,EAAE,gBAAgB,GACpB,OAAO,CAAC,eAAe,EAAE,CAAC,CAsF5B"}
|
package/dist/delivery.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { childRefKnown } from './fork.js';
|
|
2
|
-
import { completeFencedEnvelopes, createSuppressedTextStep, ensureChildSession, ensureSession, invalidateChildSession, invalidateSession, patchSession, TURN_ENVELOPE_KEY, } from './session.js';
|
|
2
|
+
import { completeFencedEnvelopes, createSuppressedTextStep, ensureChildSession, ensureSession, invalidateChildSession, invalidateSession, patchSession, TURN_ENVELOPE_KEY, turnEventsObserved, } from './session.js';
|
|
3
3
|
/**
|
|
4
4
|
* Turn-end delivery — which, under the platform reply contract, delivers
|
|
5
5
|
* NOTHING to the chat.
|
|
@@ -67,16 +67,22 @@ export async function buildParallDelivery(delivery, ctx) {
|
|
|
67
67
|
// (the npm ^1 fallback path): there turn events never arrive and, with
|
|
68
68
|
// ack-on-emit gone, this hook is the only terminal ledger path — without it
|
|
69
69
|
// a delivered turn's row would stay live and re-emit on every TTL sweep.
|
|
70
|
-
// Under the normal artifact path both hooks run; the fence makes the
|
|
71
|
-
// overlap free (whichever completes first consumes it, the other skips).
|
|
72
70
|
// Fork-handled envelopes never wrote a fence, so this is a no-op for them
|
|
73
71
|
// (their ack machinery owns the ledger there).
|
|
74
|
-
//
|
|
75
|
-
//
|
|
72
|
+
// On an OBSERVING binding this close must stand down (the turn-observed
|
|
73
|
+
// latch): the per-envelope fence makes the overlap idempotent, but not
|
|
74
|
+
// batch-safe — deliver runs before turn_completed, so closing the
|
|
75
|
+
// trigger's envelope here consumes its fence and splits the folded turn's
|
|
76
|
+
// [trigger, sibling] batch; the sibling's complete then finds no covering
|
|
77
|
+
// reply and sweeps to no_action (R-06). Cost of standing down: if the
|
|
78
|
+
// observing binding's turn_completed is lost, the fence heals via the TTL
|
|
79
|
+
// re-emit — the same recovery every lost close already relies on.
|
|
80
|
+
// Known bound of the no-observe fallback: the replyRoute snapshot carries
|
|
81
|
+
// ONE envelope id, so a folded turn's OTHER sources heal only via the TTL
|
|
76
82
|
// re-emit here. Reaching that state needs a binding with injectInFlight
|
|
77
83
|
// ON and observe OFF — the platform template always sets both together,
|
|
78
84
|
// so it exists only on a hand-crafted binding.
|
|
79
|
-
if (route.envelopeId) {
|
|
85
|
+
if (route.envelopeId && !(await turnEventsObserved(ctx))) {
|
|
80
86
|
await completeFencedEnvelopes(ctx, [route.envelopeId], 'ok');
|
|
81
87
|
}
|
|
82
88
|
const subject = route.chatId ?? route.conversationId;
|
package/dist/fork.d.ts
CHANGED
|
@@ -146,13 +146,17 @@ export declare function handleChildSpawnFailed(ctx: ConnectorContext, event: Chi
|
|
|
146
146
|
* this line keeps the child from "finishing" main's visible work).
|
|
147
147
|
*
|
|
148
148
|
* Replies are CLI-only on EVERY fork turn (the platform reply contract —
|
|
149
|
-
* nothing auto-delivers, parel-reply-contract-alignment.md). The opening
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
149
|
+
* nothing auto-delivers, parel-reply-contract-alignment.md). The opening turn
|
|
150
|
+
* has no envelope of its own (it starts from the spawn input), so its per-turn
|
|
151
|
+
* context rides the effect's `invocationContext` instead; follow-ups arrive as
|
|
152
|
+
* deliverTo envelopes carrying theirs the usual way.
|
|
153
|
+
*
|
|
154
|
+
* The prefix still spells out the full CLI reply command with the explicit chat
|
|
155
|
+
* target rather than relying on the bare `parall messages send` the system
|
|
156
|
+
* prompt teaches. That is deliberate: effects are duck-typed by the host, so a
|
|
157
|
+
* parel deployment predating `invocationContext` silently drops it, and the
|
|
158
|
+
* opening turn would then have no PRLL_CHAT_ID to default to. The explicit
|
|
159
|
+
* target costs nothing and keeps the reply path independent of that skew.
|
|
156
160
|
*/
|
|
157
161
|
export declare function buildForkScopePrefix(subject: string, threadRootId?: string): string;
|
|
158
162
|
export {};
|
package/dist/fork.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fork.d.ts","sourceRoot":"","sources":["../src/fork.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"fork.d.ts","sourceRoot":"","sources":["../src/fork.ts"],"names":[],"mappings":"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"}
|
package/dist/fork.js
CHANGED
|
@@ -314,13 +314,17 @@ export async function handleChildSpawnFailed(ctx, event) {
|
|
|
314
314
|
* this line keeps the child from "finishing" main's visible work).
|
|
315
315
|
*
|
|
316
316
|
* Replies are CLI-only on EVERY fork turn (the platform reply contract —
|
|
317
|
-
* nothing auto-delivers, parel-reply-contract-alignment.md). The opening
|
|
318
|
-
*
|
|
319
|
-
*
|
|
320
|
-
*
|
|
321
|
-
*
|
|
322
|
-
*
|
|
323
|
-
*
|
|
317
|
+
* nothing auto-delivers, parel-reply-contract-alignment.md). The opening turn
|
|
318
|
+
* has no envelope of its own (it starts from the spawn input), so its per-turn
|
|
319
|
+
* context rides the effect's `invocationContext` instead; follow-ups arrive as
|
|
320
|
+
* deliverTo envelopes carrying theirs the usual way.
|
|
321
|
+
*
|
|
322
|
+
* The prefix still spells out the full CLI reply command with the explicit chat
|
|
323
|
+
* target rather than relying on the bare `parall messages send` the system
|
|
324
|
+
* prompt teaches. That is deliberate: effects are duck-typed by the host, so a
|
|
325
|
+
* parel deployment predating `invocationContext` silently drops it, and the
|
|
326
|
+
* opening turn would then have no PRLL_CHAT_ID to default to. The explicit
|
|
327
|
+
* target costs nothing and keeps the reply path independent of that skew.
|
|
324
328
|
*/
|
|
325
329
|
export function buildForkScopePrefix(subject, threadRootId) {
|
|
326
330
|
// Quoted-heredoc input form (mirrors agent-core's send hint): plain
|
package/dist/inbound.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inbound.d.ts","sourceRoot":"","sources":["../src/inbound.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EACV,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,cAAc,EACf,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"inbound.d.ts","sourceRoot":"","sources":["../src/inbound.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EACV,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,cAAc,EACf,MAAM,mBAAmB,CAAC;AAsI3B,wBAAgB,UAAU,CAAC,CAAC,EAAE,GAAG,EAAE,gBAAgB,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAWrF;AAED,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,cAAc,EACrB,GAAG,EAAE,gBAAgB,GACpB,OAAO,CAAC,eAAe,EAAE,CAAC,CAE5B;AAoDD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,EACtB,GAAG,EAAE,gBAAgB,GACpB,OAAO,CAAC,eAAe,EAAE,CAAC,CAE5B;AAsCD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAElF;AAyoBD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,UAAU,EACjB,GAAG,EAAE,gBAAgB,GACpB,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAE7B"}
|
package/dist/inbound.js
CHANGED
|
@@ -4,7 +4,7 @@ import { armCatchUpEffect, beginCatchUp, CATCHUP_TIMER_KEY, deferToCatchUp, runC
|
|
|
4
4
|
import { parallApiUrl, parallOrgId, requireAgk, sandboxEnabled } from './connect.js';
|
|
5
5
|
import { effectsForChannelDispatch, PROVIDER_LOOKUP_TIMEOUT_MS } from './inbound-channel.js';
|
|
6
6
|
import { buildForkScopePrefix, bumpForkRetryAttempts, childConfirmed, childRefKnown, clearForkState, clearForkSubject, FORK_RETRY_DELAY_MS, FORK_RETRY_PREFIX, handleChildSpawnFailed, MAX_SPAWN_VERIFY_ATTEMPTS, noteMainTurnEvent, planForkDecision, recordSpawn, settleChildEvent, trackFollowUpAck, } from './fork.js';
|
|
7
|
-
import { ackByIdEffect, claimDispatchSource, completeFencedEnvelopes, completeSourceEffect, conversationKey, createErrorStep, createInputStep, createTraceStep, createTypedInputStep, EMIT_TTL_MS, ensureChildSession, ensureSession, invalidateChildSession, invalidateSession, nextEnvelopeId, patchSession, readActiveEmit, reportingEnabled, REQUEST_TIMEOUT_MS, TURN_ENVELOPE_KEY, writeActiveEmit, } from './session.js';
|
|
7
|
+
import { ackByIdEffect, claimDispatchSource, completeFencedEnvelopes, completeSourceEffect, conversationKey, createErrorStep, createInputStep, createTraceStep, createTypedInputStep, EMIT_TTL_MS, ensureChildSession, ensureSession, invalidateChildSession, invalidateSession, nextEnvelopeId, noteTurnEventsObserved, patchSession, readActiveEmit, reportingEnabled, REQUEST_TIMEOUT_MS, TURN_ENVELOPE_KEY, writeActiveEmit, } from './session.js';
|
|
8
8
|
import { isTypedEventType, planTypedDispatch } from './typed-dispatch.js';
|
|
9
9
|
/**
|
|
10
10
|
* Connection-keyed hook serialization — a v1-host compatibility shim. The v1
|
|
@@ -255,6 +255,10 @@ async function effectsForDispatch(data, ctx) {
|
|
|
255
255
|
// prefetch could never persist its cache row.
|
|
256
256
|
const chatName = await cachedChatName(ctx, chatId);
|
|
257
257
|
const senderId = msg?.sender_id ? String(msg.sender_id) : undefined;
|
|
258
|
+
// Structured no-reply hint (R-10): render the same [Hint: no_reply] line
|
|
259
|
+
// agent-core injects for the standard runtimes, instead of silently
|
|
260
|
+
// dropping the hint and betting on the body text.
|
|
261
|
+
const noReply = msg?.hints?.no_reply === true;
|
|
258
262
|
const framedText = buildChatPrompt({
|
|
259
263
|
chatId,
|
|
260
264
|
chatName,
|
|
@@ -262,6 +266,7 @@ async function effectsForDispatch(data, ctx) {
|
|
|
262
266
|
threadRootId,
|
|
263
267
|
text,
|
|
264
268
|
attachments,
|
|
269
|
+
noReply,
|
|
265
270
|
});
|
|
266
271
|
// Deterministic source-derived envelope id (+ attempt suffix on re-emits):
|
|
267
272
|
// complete-sources strips the suffix back to the source, and every re-emit
|
|
@@ -298,6 +303,10 @@ async function effectsForDispatch(data, ctx) {
|
|
|
298
303
|
PRLL_DISPATCH_SOURCE_TYPE: sourceType,
|
|
299
304
|
PRLL_DISPATCH_SOURCE_ID: sourceId,
|
|
300
305
|
...(threadRootId ? { PRLL_THREAD_ROOT_ID: threadRootId } : {}),
|
|
306
|
+
// Same env contract the standard runtimes' context file carries — the
|
|
307
|
+
// CLI already parses PRLL_NO_REPLY; today it is informational (prompt
|
|
308
|
+
// hint above does the suppression), but the context must not lie.
|
|
309
|
+
...(noReply ? { PRLL_NO_REPLY: '1' } : {}),
|
|
301
310
|
...(capabilityEnv ?? {}),
|
|
302
311
|
};
|
|
303
312
|
const envelope = {
|
|
@@ -464,26 +473,34 @@ async function effectsForDispatch(data, ctx) {
|
|
|
464
473
|
]);
|
|
465
474
|
if (results.includes('stale'))
|
|
466
475
|
await invalidateChildSession(ctx, decision.childRef);
|
|
476
|
+
// Same stamp — and same never-stamp-a-stale-ase_ rule — as the
|
|
477
|
+
// deliverTo branch above. Now that the opening turn carries context,
|
|
478
|
+
// its CLI reply links to the child session directly instead of
|
|
479
|
+
// resolving through dispatch provenance alone.
|
|
480
|
+
else
|
|
481
|
+
invocationContext.PRLL_SESSION_ID = childAse;
|
|
467
482
|
}
|
|
468
483
|
await recordSpawn(ctx, subject, decision.childRef, { dispatchId, sourceId });
|
|
469
484
|
await receivedSettled;
|
|
470
|
-
//
|
|
471
|
-
//
|
|
472
|
-
//
|
|
473
|
-
//
|
|
474
|
-
//
|
|
475
|
-
// the
|
|
476
|
-
//
|
|
477
|
-
//
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
485
|
+
// The opening turn gets the SAME per-turn context as any deliverTo
|
|
486
|
+
// envelope (parel `spawnChildSession.invocationContext`): PRLL_CHAT_ID,
|
|
487
|
+
// the dispatch-source pair and the session stamp reach the sandbox, and
|
|
488
|
+
// the capability env (lark-cli) is live from turn one. It used to be the
|
|
489
|
+
// single turn of a child's life that ran blind — it starts from the spawn
|
|
490
|
+
// input, not an envelope, and the effect had nowhere to carry context.
|
|
491
|
+
//
|
|
492
|
+
// A parel deployment that predates the field ignores it (effects are
|
|
493
|
+
// duck-typed, not schema-validated), which is why buildForkScopePrefix
|
|
494
|
+
// still spells out the explicit chat target: the reply path must not
|
|
495
|
+
// depend on the host having shipped this yet.
|
|
496
|
+
const spawn = {
|
|
497
|
+
type: 'spawnChildSession',
|
|
498
|
+
childRef: decision.childRef,
|
|
499
|
+
input: buildForkScopePrefix(chatId, threadRootId) + framedText,
|
|
500
|
+
subject,
|
|
501
|
+
invocationContext,
|
|
502
|
+
};
|
|
503
|
+
return [spawn, ...timerEffects];
|
|
487
504
|
}
|
|
488
505
|
// fall through: black-holed spawn rides main below.
|
|
489
506
|
}
|
|
@@ -751,6 +768,18 @@ export function handleParallAgentEvent(event, ctx) {
|
|
|
751
768
|
return serialized(ctx, () => handleParallAgentEventInner(event, ctx));
|
|
752
769
|
}
|
|
753
770
|
async function handleParallAgentEventInner(event, ctx) {
|
|
771
|
+
// Turn-observed latch (delivery.ts's close gate): ONLY the turn lifecycle
|
|
772
|
+
// proves this binding will get a turn_completed, so the deliver-side
|
|
773
|
+
// redundant close can stand down and let turn_completed settle each folded
|
|
774
|
+
// batch whole. Step events (observe: [steps] without turn) and
|
|
775
|
+
// child_spawn_failed (pushed regardless of observe scopes) reach bindings
|
|
776
|
+
// that never see a turn end — arming on those would suppress their ONLY
|
|
777
|
+
// terminal ledger path, and keep refreshing the suppression.
|
|
778
|
+
if (event.type === 'turn_started' ||
|
|
779
|
+
event.type === 'turn_completed' ||
|
|
780
|
+
event.type === 'turn_failed') {
|
|
781
|
+
await noteTurnEventsObserved(ctx);
|
|
782
|
+
}
|
|
754
783
|
// spawnChildSession's asynchronous error channel — not turn-scoped and
|
|
755
784
|
// pushed regardless of observe scopes. Handle it before anything
|
|
756
785
|
// subject-gated.
|
package/dist/session.d.ts
CHANGED
|
@@ -43,6 +43,23 @@ export declare function reportingEnabled(ctx: ConnectorContext): boolean;
|
|
|
43
43
|
*/
|
|
44
44
|
export declare const TURN_ENVELOPE_KEY = "turnEnvelope:main";
|
|
45
45
|
export declare const SESSION_CACHE_KEY = "session:main";
|
|
46
|
+
/**
|
|
47
|
+
* Turn-observed latch: proof this binding observes the TURN lifecycle, armed
|
|
48
|
+
* by turn_started / turn_completed / turn_failed only. deliver()'s redundant
|
|
49
|
+
* turn-end close exists only for bindings WITHOUT `observe: [turn]` — on an
|
|
50
|
+
* observing binding that close races turn_completed and can consume the
|
|
51
|
+
* trigger's fence FIRST, splitting a folded turn's [trigger, sibling] batch
|
|
52
|
+
* so the sibling's complete finds no covering reply and sweeps to no_action
|
|
53
|
+
* (R-06). Step events and child_spawn_failed must NOT arm it: they reach
|
|
54
|
+
* bindings that never receive a turn end, whose deliver-side close is their
|
|
55
|
+
* only terminal ledger path. The TTL keeps the fallback able to return should
|
|
56
|
+
* a binding's turn observation ever be turned off: a day with zero turn
|
|
57
|
+
* events ages the latch out and the deliver-side close resumes.
|
|
58
|
+
*/
|
|
59
|
+
export declare const TURN_EVENTS_OBSERVED_KEY = "turnEventsObserved:main";
|
|
60
|
+
export declare const TURN_OBSERVED_TTL_MS: number;
|
|
61
|
+
export declare function noteTurnEventsObserved(ctx: ConnectorContext): Promise<void>;
|
|
62
|
+
export declare function turnEventsObserved(ctx: ConnectorContext): Promise<boolean>;
|
|
46
63
|
/**
|
|
47
64
|
* Conversation key for envelope subjects and fork routing. Thread-aware:
|
|
48
65
|
* parel's turn grouping (F2) and mid-turn injection (F3) key on the envelope
|
package/dist/session.d.ts.map
CHANGED
|
@@ -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":"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"}
|
package/dist/session.js
CHANGED
|
@@ -46,6 +46,49 @@ export function reportingEnabled(ctx) {
|
|
|
46
46
|
export const TURN_ENVELOPE_KEY = `turnEnvelope:${MAIN_SESSION_KEY}`;
|
|
47
47
|
export const SESSION_CACHE_KEY = `session:${MAIN_SESSION_KEY}`;
|
|
48
48
|
const childSessionCacheKey = (childRef) => `sessionChild:${childRef}`;
|
|
49
|
+
/**
|
|
50
|
+
* Turn-observed latch: proof this binding observes the TURN lifecycle, armed
|
|
51
|
+
* by turn_started / turn_completed / turn_failed only. deliver()'s redundant
|
|
52
|
+
* turn-end close exists only for bindings WITHOUT `observe: [turn]` — on an
|
|
53
|
+
* observing binding that close races turn_completed and can consume the
|
|
54
|
+
* trigger's fence FIRST, splitting a folded turn's [trigger, sibling] batch
|
|
55
|
+
* so the sibling's complete finds no covering reply and sweeps to no_action
|
|
56
|
+
* (R-06). Step events and child_spawn_failed must NOT arm it: they reach
|
|
57
|
+
* bindings that never receive a turn end, whose deliver-side close is their
|
|
58
|
+
* only terminal ledger path. The TTL keeps the fallback able to return should
|
|
59
|
+
* a binding's turn observation ever be turned off: a day with zero turn
|
|
60
|
+
* events ages the latch out and the deliver-side close resumes.
|
|
61
|
+
*/
|
|
62
|
+
export const TURN_EVENTS_OBSERVED_KEY = `turnEventsObserved:${MAIN_SESSION_KEY}`;
|
|
63
|
+
export const TURN_OBSERVED_TTL_MS = 24 * 60 * 60 * 1000;
|
|
64
|
+
export async function noteTurnEventsObserved(ctx) {
|
|
65
|
+
// A failed write is not propagated: throwing would fail the whole hook and
|
|
66
|
+
// buy a platform replay of an event whose other effects (steps, session
|
|
67
|
+
// patches) already landed, to re-arm a latch the NEXT turn event re-arms
|
|
68
|
+
// anyway — every turn opens with turn_started. The read below is where a
|
|
69
|
+
// store failure actually has to be handled safely.
|
|
70
|
+
await ctx.store?.set(TURN_EVENTS_OBSERVED_KEY, ctx.now()).catch(() => { });
|
|
71
|
+
}
|
|
72
|
+
export async function turnEventsObserved(ctx) {
|
|
73
|
+
// No store at all: nothing was ever armed, so the fallback close is this
|
|
74
|
+
// binding's only terminal path — it must run.
|
|
75
|
+
if (!ctx.store)
|
|
76
|
+
return false;
|
|
77
|
+
let at;
|
|
78
|
+
try {
|
|
79
|
+
at = await ctx.store.get(TURN_EVENTS_OBSERVED_KEY);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
// A transient read failure must NOT read as "this binding does not observe
|
|
83
|
+
// turns". That answer runs the deliver-side close, the destructive branch:
|
|
84
|
+
// it consumes the trigger's fence and can split a folded batch, which is
|
|
85
|
+
// R-06 itself. Failing closed costs at most a missed fallback close, which
|
|
86
|
+
// the existing 30min TTL re-emit heals; failing open costs a sibling swept
|
|
87
|
+
// to no_action, which nothing recovers.
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
return typeof at === 'number' && ctx.now() - at < TURN_OBSERVED_TTL_MS;
|
|
91
|
+
}
|
|
49
92
|
/**
|
|
50
93
|
* Conversation key for envelope subjects and fork routing. Thread-aware:
|
|
51
94
|
* parel's turn grouping (F2) and mid-turn injection (F3) key on the envelope
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parall/parel-channel",
|
|
3
|
-
"version": "1.52.
|
|
3
|
+
"version": "1.52.2",
|
|
4
4
|
"description": "Parall channel plugin for the parel runtime — lets a parel agent treat Parall as a managed_ws channel (receive dispatches, reply via the Parall API)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
package/src/channel-prompt.ts
CHANGED
|
@@ -52,6 +52,8 @@ export interface ChatPromptArgs {
|
|
|
52
52
|
text: string;
|
|
53
53
|
/** Message attachments — rendered as reference lines (agent fetches via CLI). */
|
|
54
54
|
attachments?: PromptAttachment[];
|
|
55
|
+
/** message.hints.no_reply — rendered as the same [Hint: no_reply] line agent-core injects. */
|
|
56
|
+
noReply?: boolean;
|
|
55
57
|
}
|
|
56
58
|
|
|
57
59
|
/**
|
|
@@ -84,6 +86,7 @@ export function buildChatPrompt(args: ChatPromptArgs): string {
|
|
|
84
86
|
const lines = [`[Chat: ${chatLabel}]`];
|
|
85
87
|
if (args.senderId) lines.push(`[From: ${sanitizeMeta(args.senderId)}]`);
|
|
86
88
|
if (args.threadRootId) lines.push(`[Thread: ${sanitizeMeta(args.threadRootId)}]`);
|
|
89
|
+
if (args.noReply) lines.push(`[Hint: no_reply]`);
|
|
87
90
|
lines.push(...attachmentLines(args.attachments));
|
|
88
91
|
lines.push('', args.text);
|
|
89
92
|
return lines.join('\n');
|
package/src/delivery.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
invalidateSession,
|
|
10
10
|
patchSession,
|
|
11
11
|
TURN_ENVELOPE_KEY,
|
|
12
|
+
turnEventsObserved,
|
|
12
13
|
} from './session.js';
|
|
13
14
|
|
|
14
15
|
/**
|
|
@@ -89,16 +90,22 @@ export async function buildParallDelivery(
|
|
|
89
90
|
// (the npm ^1 fallback path): there turn events never arrive and, with
|
|
90
91
|
// ack-on-emit gone, this hook is the only terminal ledger path — without it
|
|
91
92
|
// a delivered turn's row would stay live and re-emit on every TTL sweep.
|
|
92
|
-
// Under the normal artifact path both hooks run; the fence makes the
|
|
93
|
-
// overlap free (whichever completes first consumes it, the other skips).
|
|
94
93
|
// Fork-handled envelopes never wrote a fence, so this is a no-op for them
|
|
95
94
|
// (their ack machinery owns the ledger there).
|
|
96
|
-
//
|
|
97
|
-
//
|
|
95
|
+
// On an OBSERVING binding this close must stand down (the turn-observed
|
|
96
|
+
// latch): the per-envelope fence makes the overlap idempotent, but not
|
|
97
|
+
// batch-safe — deliver runs before turn_completed, so closing the
|
|
98
|
+
// trigger's envelope here consumes its fence and splits the folded turn's
|
|
99
|
+
// [trigger, sibling] batch; the sibling's complete then finds no covering
|
|
100
|
+
// reply and sweeps to no_action (R-06). Cost of standing down: if the
|
|
101
|
+
// observing binding's turn_completed is lost, the fence heals via the TTL
|
|
102
|
+
// re-emit — the same recovery every lost close already relies on.
|
|
103
|
+
// Known bound of the no-observe fallback: the replyRoute snapshot carries
|
|
104
|
+
// ONE envelope id, so a folded turn's OTHER sources heal only via the TTL
|
|
98
105
|
// re-emit here. Reaching that state needs a binding with injectInFlight
|
|
99
106
|
// ON and observe OFF — the platform template always sets both together,
|
|
100
107
|
// so it exists only on a hand-crafted binding.
|
|
101
|
-
if (route.envelopeId) {
|
|
108
|
+
if (route.envelopeId && !(await turnEventsObserved(ctx))) {
|
|
102
109
|
await completeFencedEnvelopes(ctx, [route.envelopeId], 'ok');
|
|
103
110
|
}
|
|
104
111
|
|
package/src/fork.ts
CHANGED
|
@@ -426,13 +426,17 @@ export async function handleChildSpawnFailed(
|
|
|
426
426
|
* this line keeps the child from "finishing" main's visible work).
|
|
427
427
|
*
|
|
428
428
|
* Replies are CLI-only on EVERY fork turn (the platform reply contract —
|
|
429
|
-
* nothing auto-delivers, parel-reply-contract-alignment.md). The opening
|
|
430
|
-
*
|
|
431
|
-
*
|
|
432
|
-
*
|
|
433
|
-
*
|
|
434
|
-
*
|
|
435
|
-
*
|
|
429
|
+
* nothing auto-delivers, parel-reply-contract-alignment.md). The opening turn
|
|
430
|
+
* has no envelope of its own (it starts from the spawn input), so its per-turn
|
|
431
|
+
* context rides the effect's `invocationContext` instead; follow-ups arrive as
|
|
432
|
+
* deliverTo envelopes carrying theirs the usual way.
|
|
433
|
+
*
|
|
434
|
+
* The prefix still spells out the full CLI reply command with the explicit chat
|
|
435
|
+
* target rather than relying on the bare `parall messages send` the system
|
|
436
|
+
* prompt teaches. That is deliberate: effects are duck-typed by the host, so a
|
|
437
|
+
* parel deployment predating `invocationContext` silently drops it, and the
|
|
438
|
+
* opening turn would then have no PRLL_CHAT_ID to default to. The explicit
|
|
439
|
+
* target costs nothing and keeps the reply path independent of that skew.
|
|
436
440
|
*/
|
|
437
441
|
export function buildForkScopePrefix(subject: string, threadRootId?: string): string {
|
|
438
442
|
// Quoted-heredoc input form (mirrors agent-core's send hint): plain
|
package/src/inbound.ts
CHANGED
|
@@ -49,6 +49,7 @@ import {
|
|
|
49
49
|
invalidateChildSession,
|
|
50
50
|
invalidateSession,
|
|
51
51
|
nextEnvelopeId,
|
|
52
|
+
noteTurnEventsObserved,
|
|
52
53
|
patchSession,
|
|
53
54
|
readActiveEmit,
|
|
54
55
|
reportingEnabled,
|
|
@@ -96,6 +97,18 @@ import { isTypedEventType, planTypedDispatch } from './typed-dispatch.js';
|
|
|
96
97
|
* pending rather than being acked-and-dropped.
|
|
97
98
|
*/
|
|
98
99
|
|
|
100
|
+
/**
|
|
101
|
+
* The spawn effect plus parel's `invocationContext`, which carries per-turn
|
|
102
|
+
* context into the child's opening turn. The field is native in
|
|
103
|
+
* `@parel/plugin-sdk` 0.14.0, but this package still resolves `^0.12.0` and a
|
|
104
|
+
* 0.x caret never crosses minors — so the alias stays until that dependency is
|
|
105
|
+
* bumped, then it can go. Effects are duck-typed by the host, so an older parel
|
|
106
|
+
* deployment ignores the field rather than rejecting the spawn.
|
|
107
|
+
*/
|
|
108
|
+
type SpawnChildEffect = Extract<ConnectorEffect, { type: 'spawnChildSession' }> & {
|
|
109
|
+
invocationContext?: Record<string, unknown>;
|
|
110
|
+
};
|
|
111
|
+
|
|
99
112
|
interface DispatchData {
|
|
100
113
|
id?: unknown;
|
|
101
114
|
event_type?: unknown;
|
|
@@ -355,6 +368,7 @@ async function effectsForDispatch(
|
|
|
355
368
|
content?: { text?: string };
|
|
356
369
|
thread_root_id?: string;
|
|
357
370
|
sender_id?: string;
|
|
371
|
+
hints?: { no_reply?: boolean };
|
|
358
372
|
attachments?: Array<{
|
|
359
373
|
id?: string;
|
|
360
374
|
file_name?: string;
|
|
@@ -392,6 +406,10 @@ async function effectsForDispatch(
|
|
|
392
406
|
// prefetch could never persist its cache row.
|
|
393
407
|
const chatName = await cachedChatName(ctx, chatId);
|
|
394
408
|
const senderId = msg?.sender_id ? String(msg.sender_id) : undefined;
|
|
409
|
+
// Structured no-reply hint (R-10): render the same [Hint: no_reply] line
|
|
410
|
+
// agent-core injects for the standard runtimes, instead of silently
|
|
411
|
+
// dropping the hint and betting on the body text.
|
|
412
|
+
const noReply = msg?.hints?.no_reply === true;
|
|
395
413
|
const framedText = buildChatPrompt({
|
|
396
414
|
chatId,
|
|
397
415
|
chatName,
|
|
@@ -399,6 +417,7 @@ async function effectsForDispatch(
|
|
|
399
417
|
threadRootId,
|
|
400
418
|
text,
|
|
401
419
|
attachments,
|
|
420
|
+
noReply,
|
|
402
421
|
});
|
|
403
422
|
// Deterministic source-derived envelope id (+ attempt suffix on re-emits):
|
|
404
423
|
// complete-sources strips the suffix back to the source, and every re-emit
|
|
@@ -437,6 +456,10 @@ async function effectsForDispatch(
|
|
|
437
456
|
PRLL_DISPATCH_SOURCE_TYPE: sourceType,
|
|
438
457
|
PRLL_DISPATCH_SOURCE_ID: sourceId,
|
|
439
458
|
...(threadRootId ? { PRLL_THREAD_ROOT_ID: threadRootId } : {}),
|
|
459
|
+
// Same env contract the standard runtimes' context file carries — the
|
|
460
|
+
// CLI already parses PRLL_NO_REPLY; today it is informational (prompt
|
|
461
|
+
// hint above does the suppression), but the context must not lie.
|
|
462
|
+
...(noReply ? { PRLL_NO_REPLY: '1' } : {}),
|
|
440
463
|
...(capabilityEnv ?? {}),
|
|
441
464
|
};
|
|
442
465
|
|
|
@@ -603,26 +626,33 @@ async function effectsForDispatch(
|
|
|
603
626
|
}),
|
|
604
627
|
]);
|
|
605
628
|
if (results.includes('stale')) await invalidateChildSession(ctx, decision.childRef);
|
|
629
|
+
// Same stamp — and same never-stamp-a-stale-ase_ rule — as the
|
|
630
|
+
// deliverTo branch above. Now that the opening turn carries context,
|
|
631
|
+
// its CLI reply links to the child session directly instead of
|
|
632
|
+
// resolving through dispatch provenance alone.
|
|
633
|
+
else invocationContext.PRLL_SESSION_ID = childAse;
|
|
606
634
|
}
|
|
607
635
|
await recordSpawn(ctx, subject, decision.childRef, { dispatchId, sourceId });
|
|
608
636
|
await receivedSettled;
|
|
609
|
-
//
|
|
610
|
-
//
|
|
611
|
-
//
|
|
612
|
-
//
|
|
613
|
-
//
|
|
614
|
-
// the
|
|
615
|
-
//
|
|
616
|
-
//
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
637
|
+
// The opening turn gets the SAME per-turn context as any deliverTo
|
|
638
|
+
// envelope (parel `spawnChildSession.invocationContext`): PRLL_CHAT_ID,
|
|
639
|
+
// the dispatch-source pair and the session stamp reach the sandbox, and
|
|
640
|
+
// the capability env (lark-cli) is live from turn one. It used to be the
|
|
641
|
+
// single turn of a child's life that ran blind — it starts from the spawn
|
|
642
|
+
// input, not an envelope, and the effect had nowhere to carry context.
|
|
643
|
+
//
|
|
644
|
+
// A parel deployment that predates the field ignores it (effects are
|
|
645
|
+
// duck-typed, not schema-validated), which is why buildForkScopePrefix
|
|
646
|
+
// still spells out the explicit chat target: the reply path must not
|
|
647
|
+
// depend on the host having shipped this yet.
|
|
648
|
+
const spawn: SpawnChildEffect = {
|
|
649
|
+
type: 'spawnChildSession',
|
|
650
|
+
childRef: decision.childRef,
|
|
651
|
+
input: buildForkScopePrefix(chatId, threadRootId) + framedText,
|
|
652
|
+
subject,
|
|
653
|
+
invocationContext,
|
|
654
|
+
};
|
|
655
|
+
return [spawn, ...timerEffects];
|
|
626
656
|
}
|
|
627
657
|
// fall through: black-holed spawn rides main below.
|
|
628
658
|
}
|
|
@@ -917,6 +947,20 @@ async function handleParallAgentEventInner(
|
|
|
917
947
|
event: AgentEvent,
|
|
918
948
|
ctx: ConnectorContext,
|
|
919
949
|
): Promise<AgentEventEffect[]> {
|
|
950
|
+
// Turn-observed latch (delivery.ts's close gate): ONLY the turn lifecycle
|
|
951
|
+
// proves this binding will get a turn_completed, so the deliver-side
|
|
952
|
+
// redundant close can stand down and let turn_completed settle each folded
|
|
953
|
+
// batch whole. Step events (observe: [steps] without turn) and
|
|
954
|
+
// child_spawn_failed (pushed regardless of observe scopes) reach bindings
|
|
955
|
+
// that never see a turn end — arming on those would suppress their ONLY
|
|
956
|
+
// terminal ledger path, and keep refreshing the suppression.
|
|
957
|
+
if (
|
|
958
|
+
event.type === 'turn_started' ||
|
|
959
|
+
event.type === 'turn_completed' ||
|
|
960
|
+
event.type === 'turn_failed'
|
|
961
|
+
) {
|
|
962
|
+
await noteTurnEventsObserved(ctx);
|
|
963
|
+
}
|
|
920
964
|
// spawnChildSession's asynchronous error channel — not turn-scoped and
|
|
921
965
|
// pushed regardless of observe scopes. Handle it before anything
|
|
922
966
|
// subject-gated.
|
package/src/session.ts
CHANGED
|
@@ -53,6 +53,50 @@ export const TURN_ENVELOPE_KEY = `turnEnvelope:${MAIN_SESSION_KEY}`;
|
|
|
53
53
|
export const SESSION_CACHE_KEY = `session:${MAIN_SESSION_KEY}`;
|
|
54
54
|
const childSessionCacheKey = (childRef: string) => `sessionChild:${childRef}`;
|
|
55
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Turn-observed latch: proof this binding observes the TURN lifecycle, armed
|
|
58
|
+
* by turn_started / turn_completed / turn_failed only. deliver()'s redundant
|
|
59
|
+
* turn-end close exists only for bindings WITHOUT `observe: [turn]` — on an
|
|
60
|
+
* observing binding that close races turn_completed and can consume the
|
|
61
|
+
* trigger's fence FIRST, splitting a folded turn's [trigger, sibling] batch
|
|
62
|
+
* so the sibling's complete finds no covering reply and sweeps to no_action
|
|
63
|
+
* (R-06). Step events and child_spawn_failed must NOT arm it: they reach
|
|
64
|
+
* bindings that never receive a turn end, whose deliver-side close is their
|
|
65
|
+
* only terminal ledger path. The TTL keeps the fallback able to return should
|
|
66
|
+
* a binding's turn observation ever be turned off: a day with zero turn
|
|
67
|
+
* events ages the latch out and the deliver-side close resumes.
|
|
68
|
+
*/
|
|
69
|
+
export const TURN_EVENTS_OBSERVED_KEY = `turnEventsObserved:${MAIN_SESSION_KEY}`;
|
|
70
|
+
export const TURN_OBSERVED_TTL_MS = 24 * 60 * 60 * 1000;
|
|
71
|
+
|
|
72
|
+
export async function noteTurnEventsObserved(ctx: ConnectorContext): Promise<void> {
|
|
73
|
+
// A failed write is not propagated: throwing would fail the whole hook and
|
|
74
|
+
// buy a platform replay of an event whose other effects (steps, session
|
|
75
|
+
// patches) already landed, to re-arm a latch the NEXT turn event re-arms
|
|
76
|
+
// anyway — every turn opens with turn_started. The read below is where a
|
|
77
|
+
// store failure actually has to be handled safely.
|
|
78
|
+
await ctx.store?.set(TURN_EVENTS_OBSERVED_KEY, ctx.now()).catch(() => {});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export async function turnEventsObserved(ctx: ConnectorContext): Promise<boolean> {
|
|
82
|
+
// No store at all: nothing was ever armed, so the fallback close is this
|
|
83
|
+
// binding's only terminal path — it must run.
|
|
84
|
+
if (!ctx.store) return false;
|
|
85
|
+
let at: unknown;
|
|
86
|
+
try {
|
|
87
|
+
at = await ctx.store.get(TURN_EVENTS_OBSERVED_KEY);
|
|
88
|
+
} catch {
|
|
89
|
+
// A transient read failure must NOT read as "this binding does not observe
|
|
90
|
+
// turns". That answer runs the deliver-side close, the destructive branch:
|
|
91
|
+
// it consumes the trigger's fence and can split a folded batch, which is
|
|
92
|
+
// R-06 itself. Failing closed costs at most a missed fallback close, which
|
|
93
|
+
// the existing 30min TTL re-emit heals; failing open costs a sibling swept
|
|
94
|
+
// to no_action, which nothing recovers.
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
return typeof at === 'number' && ctx.now() - at < TURN_OBSERVED_TTL_MS;
|
|
98
|
+
}
|
|
99
|
+
|
|
56
100
|
/**
|
|
57
101
|
* Conversation key for envelope subjects and fork routing. Thread-aware:
|
|
58
102
|
* parel's turn grouping (F2) and mid-turn injection (F3) key on the envelope
|