@parall/parall 1.43.0 → 1.45.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/gateway.d.ts.map +1 -1
- package/dist/gateway.js +28 -1
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +58 -0
- package/dist/index.bundle.mjs +498 -97
- package/dist/runtime.d.ts +17 -0
- package/dist/runtime.d.ts.map +1 -1
- package/package.json +3 -3
- package/skills/parall-schedules/SKILL.md +1 -1
- package/skills/parall-tasks/SKILL.md +21 -5
- package/src/gateway.ts +31 -0
- package/src/hooks.ts +60 -0
- package/src/runtime.ts +17 -0
package/dist/runtime.d.ts
CHANGED
|
@@ -16,6 +16,23 @@ export type ParallAccountState = {
|
|
|
16
16
|
wikiMountRoot?: string;
|
|
17
17
|
ws?: ParallWs;
|
|
18
18
|
orchestratorSessionKey?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Per-lane dispatch context dir (PRLL_CONTEXT_DIR contract) — set when the
|
|
21
|
+
* gateway runs the dispatch ledger; hooks inject it into exec env so the
|
|
22
|
+
* CLI binds replies to their dispatch lane.
|
|
23
|
+
*/
|
|
24
|
+
dispatchContextDir?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Per-session dispatch context file resolver (PRLL_CONTEXT_FILE contract)
|
|
27
|
+
* — the CLI's typed dispatch binding (task_update effects) reads from it.
|
|
28
|
+
*/
|
|
29
|
+
contextFilePathForSession?: (sessionKey: string) => string;
|
|
30
|
+
/**
|
|
31
|
+
* Lease-renewal bridge into the gateway: openclaw tool activity flows
|
|
32
|
+
* through hooks (not the RuntimeEvent stream), so hooks must forward it or
|
|
33
|
+
* a long exec outlives the lane lease.
|
|
34
|
+
*/
|
|
35
|
+
touchRuntimeActivity?: (sessionKey: string) => void;
|
|
19
36
|
[key: string]: unknown;
|
|
20
37
|
};
|
|
21
38
|
export declare function setParallRuntime(next: PluginRuntime): void;
|
package/dist/runtime.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjF,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,EACpB,sBAAsB,EACtB,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,EAAE,CAAC,EAAE,QAAQ,CAAC;IACd,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAIF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,aAAa,QAEnD;AAED,wBAAgB,gBAAgB,IAAI,aAAa,CAKhD;AAKD,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,QAEjF;AAED,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,QAEzD;AAED,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS,CAEvF;AAED,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,QAOvB;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEhG;AAED,wBAAgB,yBAAyB,IAAI,WAAW,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAEnF;AAID,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,aAAa,QAEvD;AAED,wBAAgB,gBAAgB,IAAI,aAAa,GAAG,SAAS,CAE5D"}
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjF,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,EACpB,sBAAsB,EACtB,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,EAAE,CAAC,EAAE,QAAQ,CAAC;IACd,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;OAGG;IACH,yBAAyB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,CAAC;IAC3D;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAIF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,aAAa,QAEnD;AAED,wBAAgB,gBAAgB,IAAI,aAAa,CAKhD;AAKD,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,QAEjF;AAED,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,QAEzD;AAED,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS,CAEvF;AAED,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,QAOvB;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEhG;AAED,wBAAgB,yBAAyB,IAAI,WAAW,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAEnF;AAID,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,aAAa,QAEvD;AAED,wBAAgB,gBAAgB,IAAI,aAAa,GAAG,SAAS,CAE5D"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parall/parall",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.45.0",
|
|
4
4
|
"description": "OpenClaw channel plugin for Parall IM",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
"openclaw.plugin.json"
|
|
17
17
|
],
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@parall/
|
|
20
|
-
"@parall/
|
|
19
|
+
"@parall/sdk": "1.45.0",
|
|
20
|
+
"@parall/agent-core": "1.45.0"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"@types/node": "^22.0.0",
|
|
@@ -40,7 +40,7 @@ parall schedules create \
|
|
|
40
40
|
--run-at <FUTURE_RFC3339_TIME>
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
`--target-ids` is who receives the fire (usually yourself when you're self-scheduling; another agent or human when delegating). `--attached-to-uri` optionally anchors the schedule to a task / chat / project / wiki page — when that resource is archived or deleted, the schedule auto-cancels (`
|
|
43
|
+
`--target-ids` is who receives the fire (usually yourself when you're self-scheduling; another agent or human when delegating). `--attached-to-uri` optionally anchors the schedule to a task / chat / project / wiki page — when that resource is archived or deleted, the schedule auto-cancels (`status_reason=attached_gone`). A schedule whose agent targets all sit on a terminated machine is auto-paused by the platform (`status_reason=attendee_unreachable`) instead of firing into a void; resuming a recurring schedule while the machine is still terminated just pauses it again on the next slot (a one-shot resumed past its catch-up window instead follows the normal missed semantics and completes).
|
|
44
44
|
|
|
45
45
|
### Reminders for someone else
|
|
46
46
|
|
|
@@ -39,16 +39,32 @@ parall tasks list --assignee-id prll://usr_xxx # first page only (default 20)
|
|
|
39
39
|
parall tasks subtasks prll://tsk_xxx # children of a single parent task
|
|
40
40
|
|
|
41
41
|
# Create a task (add --parent-id to make it a SUBTASK of another task)
|
|
42
|
-
parall tasks create --title "Task title" [--assignee-id prll://usr_xxx] [--parent-id prll://tsk_xxx] [--project-id prll://prj_xxx]
|
|
42
|
+
parall tasks create --title "Task title" [--assignee-id prll://usr_xxx] [--parent-id prll://tsk_xxx] [--project-id prll://prj_xxx] [--due-date 2026-08-01]
|
|
43
43
|
|
|
44
|
-
# Update task status
|
|
45
|
-
|
|
46
|
-
parall tasks update prll://tsk_xxx --status
|
|
44
|
+
# Update task status — add --placement end so the task lands at the end of
|
|
45
|
+
# its NEW status column (a bare --status keeps the old column's sort_order)
|
|
46
|
+
parall tasks update prll://tsk_xxx --status in_progress --placement end
|
|
47
|
+
parall tasks update prll://tsk_xxx --status done --placement end
|
|
48
|
+
|
|
49
|
+
# Due date — a plain YYYY-MM-DD date (no timestamps); "none" clears it
|
|
50
|
+
parall tasks update prll://tsk_xxx --due-date 2026-08-01
|
|
51
|
+
parall tasks update prll://tsk_xxx --due-date none
|
|
52
|
+
|
|
53
|
+
# Move a task to the end of its status column
|
|
54
|
+
parall tasks update prll://tsk_xxx --placement end
|
|
47
55
|
|
|
48
56
|
# Add a comment
|
|
49
57
|
parall tasks comments add prll://tsk_xxx --body "Progress update..."
|
|
50
58
|
```
|
|
51
59
|
|
|
60
|
+
Ordering: to append a task to the end of a status column, always use
|
|
61
|
+
`--placement end` — the server resolves the position atomically. This
|
|
62
|
+
includes status changes: a bare `--status` keeps the task's old
|
|
63
|
+
`sort_order`, which may collide inside the new column. Do NOT compute a
|
|
64
|
+
`sort_order` value yourself from listed tasks (your view may be stale or
|
|
65
|
+
partial). `--sort-order` is only for pinpoint insertion between two cards
|
|
66
|
+
you just listed, and it cannot be combined with `--placement`.
|
|
67
|
+
|
|
52
68
|
Subtasks are just tasks with a parent: create one with `tasks create --parent-id`,
|
|
53
69
|
re-parent with `tasks update --parent-id`, list a parent's children with
|
|
54
70
|
`tasks subtasks`. `tasks list` without `--parent-id` already returns both
|
|
@@ -83,7 +99,7 @@ watcher.
|
|
|
83
99
|
When you receive `[Event: task.assigned]`:
|
|
84
100
|
|
|
85
101
|
1. Acknowledge with a comment: `tasks comments add prll://tsk_xxx --body "On it"`
|
|
86
|
-
2. Update status: `tasks update prll://tsk_xxx --status in_progress`
|
|
102
|
+
2. Update status: `tasks update prll://tsk_xxx --status in_progress --placement end`
|
|
87
103
|
3. Do the work
|
|
88
104
|
4. Report results in a comment. If a gate remains — review, merge, deploy,
|
|
89
105
|
requester acceptance — set `in_review` and name the gate; set `done`
|
package/src/gateway.ts
CHANGED
|
@@ -6,6 +6,7 @@ type ChannelGatewayAdapter<T = unknown> = NonNullable<ChannelPlugin<T>['gateway'
|
|
|
6
6
|
import {
|
|
7
7
|
ParallAgentGateway,
|
|
8
8
|
capabilityBinDir,
|
|
9
|
+
dispatchLaneContextDir,
|
|
9
10
|
parseShutdownDeadlineMs,
|
|
10
11
|
parseForkDeadlineMs,
|
|
11
12
|
parseDispatchDeadlineMs,
|
|
@@ -47,6 +48,16 @@ import {
|
|
|
47
48
|
resolveTranscriptFile,
|
|
48
49
|
} from './fork.js';
|
|
49
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Per-session dispatch context file (PRLL_CONTEXT_FILE contract) — same
|
|
53
|
+
* encoding as the claude/codex bridges: base64url(sessionKey) under the
|
|
54
|
+
* state dir's dispatch-context/.
|
|
55
|
+
*/
|
|
56
|
+
function sessionContextFilePath(stateDir: string, sessionKey: string): string {
|
|
57
|
+
const fileName = Buffer.from(sessionKey).toString('base64url');
|
|
58
|
+
return path.join(stateDir, 'dispatch-context', `${fileName}.json`);
|
|
59
|
+
}
|
|
60
|
+
|
|
50
61
|
function resolveWsUrl(account: ResolvedParallAccount): string {
|
|
51
62
|
if (account.config.ws_url) return account.config.ws_url;
|
|
52
63
|
const base = account.config.parall_url.replace(/\/$/, '');
|
|
@@ -482,6 +493,19 @@ export const parallGateway: ChannelGatewayAdapter<ResolvedParallAccount> = {
|
|
|
482
493
|
runtimeKey: orchestratorKey,
|
|
483
494
|
runtimeRef: { hostname: os.hostname(), pid: process.pid },
|
|
484
495
|
dispatchAdapter,
|
|
496
|
+
// Opts openclaw into the dispatch ledger (claim/fold/complete +
|
|
497
|
+
// idempotent reply effects) — the same shared-gateway machinery
|
|
498
|
+
// claude/codex ride; openclaw stays buffer-only (no mid-turn steer),
|
|
499
|
+
// which the ledger does not require. Replies already flow through
|
|
500
|
+
// @parall/cli, which reads PRLL_CONTEXT_DIR (injected in hooks.ts)
|
|
501
|
+
// to bind dispatch_lane + reply effect keys.
|
|
502
|
+
// Design: docs/engineering-design/dispatch-convergence-design.md §7 (S2).
|
|
503
|
+
dispatchContextDir: dispatchLaneContextDir(stateDir),
|
|
504
|
+
// Per-session context file (PRLL_CONTEXT_FILE contract) — the CLI's
|
|
505
|
+
// TYPED dispatch binding (parall tasks update → task_update effect)
|
|
506
|
+
// reads lane/event/task fields from this file, not the lane dir.
|
|
507
|
+
contextFilePathForSession: (sessionKey: string) =>
|
|
508
|
+
sessionContextFilePath(stateDir, sessionKey),
|
|
485
509
|
log: otelLog,
|
|
486
510
|
// Live capability view for hint routing: the channel reply hint
|
|
487
511
|
// points at the vendor CLI only while the grant is active.
|
|
@@ -506,6 +530,13 @@ export const parallGateway: ChannelGatewayAdapter<ResolvedParallAccount> = {
|
|
|
506
530
|
wikiMountRoot,
|
|
507
531
|
ws,
|
|
508
532
|
orchestratorSessionKey: orchestratorKey,
|
|
533
|
+
dispatchContextDir: dispatchLaneContextDir(stateDir),
|
|
534
|
+
contextFilePathForSession: (sessionKey: string) =>
|
|
535
|
+
sessionContextFilePath(stateDir, sessionKey),
|
|
536
|
+
// Lease-renewal bridge: openclaw tool calls flow through hooks,
|
|
537
|
+
// not the RuntimeEvent stream, so hook activity must renew the
|
|
538
|
+
// ledger lanes or a long exec outlives the lease (STALE_LANE).
|
|
539
|
+
touchRuntimeActivity: (sessionKey: string) => gateway.touchRuntimeActivity(sessionKey),
|
|
509
540
|
});
|
|
510
541
|
},
|
|
511
542
|
onSessionBinding: async ({ sessionKey, agentSessionId }) => {
|
package/src/hooks.ts
CHANGED
|
@@ -140,6 +140,49 @@ export function registerParallHooks(api: OpenClawPluginApi) {
|
|
|
140
140
|
|
|
141
141
|
const pendingSendCalls = new Map<string, boolean>();
|
|
142
142
|
|
|
143
|
+
// Lane lease keepalive across the tool-call lifecycle. OpenClaw tool calls
|
|
144
|
+
// bypass the RuntimeEvent stream, so lane renewal must ride these hooks —
|
|
145
|
+
// and a ONE-SHOT touch at tool start is not enough: a single exec running
|
|
146
|
+
// past the lane TTL (10min server-side) would still be dethroned mid-call
|
|
147
|
+
// and the eventual CLI reply would die with STALE_LANE. While any tool call
|
|
148
|
+
// is in flight for a session, an unref'd interval keeps touching; the
|
|
149
|
+
// half-TTL throttle in the ledger decides when a real heartbeat is sent.
|
|
150
|
+
const laneRenewals = new Map<string, { count: number; timer?: ReturnType<typeof setInterval> }>();
|
|
151
|
+
const LANE_RENEW_INTERVAL_MS = 180_000;
|
|
152
|
+
|
|
153
|
+
const beginToolRenewal = (sessionKey: string) => {
|
|
154
|
+
const accountId = extractAccountIdFromSessionKey(sessionKey);
|
|
155
|
+
const state = accountId ? getParallAccountState(accountId) : undefined;
|
|
156
|
+
if (!state?.touchRuntimeActivity) return;
|
|
157
|
+
state.touchRuntimeActivity(sessionKey);
|
|
158
|
+
const entry = laneRenewals.get(sessionKey) ?? { count: 0 };
|
|
159
|
+
entry.count++;
|
|
160
|
+
if (!entry.timer) {
|
|
161
|
+
entry.timer = setInterval(
|
|
162
|
+
() => state.touchRuntimeActivity?.(sessionKey),
|
|
163
|
+
LANE_RENEW_INTERVAL_MS,
|
|
164
|
+
);
|
|
165
|
+
entry.timer.unref?.();
|
|
166
|
+
}
|
|
167
|
+
laneRenewals.set(sessionKey, entry);
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
const endToolRenewal = (sessionKey: string) => {
|
|
171
|
+
const entry = laneRenewals.get(sessionKey);
|
|
172
|
+
if (entry) {
|
|
173
|
+
entry.count--;
|
|
174
|
+
if (entry.count <= 0) {
|
|
175
|
+
if (entry.timer) clearInterval(entry.timer);
|
|
176
|
+
laneRenewals.delete(sessionKey);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
const accountId = extractAccountIdFromSessionKey(sessionKey);
|
|
180
|
+
const state = accountId ? getParallAccountState(accountId) : undefined;
|
|
181
|
+
// Final touch on completion — covers the reply window right after a
|
|
182
|
+
// long tool call ends.
|
|
183
|
+
state?.touchRuntimeActivity?.(sessionKey);
|
|
184
|
+
};
|
|
185
|
+
|
|
143
186
|
// before_tool_call -> (1) update dispatch metrics, (2) await step creation, (3) ENV injection
|
|
144
187
|
// OpenClaw tool calls bypass the RuntimeEvent stream (they go through hooks, not the
|
|
145
188
|
// gateway-base for-await loop), so dispatch metrics must be updated here as well.
|
|
@@ -147,6 +190,9 @@ export function registerParallHooks(api: OpenClawPluginApi) {
|
|
|
147
190
|
const sessionKey = ctx.sessionKey;
|
|
148
191
|
if (sessionKey) {
|
|
149
192
|
recordToolCall(sessionKey);
|
|
193
|
+
// Every tool (not just exec) keeps the ledger lane alive for its
|
|
194
|
+
// whole lifetime — see laneRenewals above.
|
|
195
|
+
beginToolRenewal(sessionKey);
|
|
150
196
|
if (event.toolName === 'exec' && event.toolCallId) {
|
|
151
197
|
const command = (event.params as Record<string, unknown>)?.command as string | undefined;
|
|
152
198
|
if (isParallSendCommand(command)) {
|
|
@@ -228,6 +274,19 @@ export function registerParallHooks(api: OpenClawPluginApi) {
|
|
|
228
274
|
}
|
|
229
275
|
if (triggerMsgId) injectedEnv.PRLL_TRIGGER_MESSAGE_ID = triggerMsgId;
|
|
230
276
|
if (state.wikiMountRoot) injectedEnv.PRLL_WIKI_MOUNT_ROOT = state.wikiMountRoot;
|
|
277
|
+
// Dispatch-ledger contract: the CLI keys into this directory by send
|
|
278
|
+
// target to bind dispatch_lane + the reply:<dsp> effect key (idempotent
|
|
279
|
+
// replies). Set only when the gateway runs the ledger.
|
|
280
|
+
if (state.dispatchContextDir) injectedEnv.PRLL_CONTEXT_DIR = state.dispatchContextDir;
|
|
281
|
+
// Per-session context file — the CLI's TYPED binding (parall tasks
|
|
282
|
+
// update → task_update:<dsp> effect) reads lane/event/task from here.
|
|
283
|
+
if (state.contextFilePathForSession) {
|
|
284
|
+
injectedEnv.PRLL_CONTEXT_FILE = state.contextFilePathForSession(sessionKey);
|
|
285
|
+
}
|
|
286
|
+
// Long tool calls bypass the RuntimeEvent stream — forward activity so
|
|
287
|
+
// the ledger lane lease renews (a >TTL exec would otherwise be dethroned
|
|
288
|
+
// mid-turn and the eventual CLI reply would die with STALE_LANE).
|
|
289
|
+
state.touchRuntimeActivity?.(sessionKey);
|
|
231
290
|
|
|
232
291
|
// OpenClaw context (upstream doesn't inject these into exec env yet)
|
|
233
292
|
injectedEnv.OPENCLAW_SESSION_KEY = sessionKey;
|
|
@@ -247,6 +306,7 @@ export function registerParallHooks(api: OpenClawPluginApi) {
|
|
|
247
306
|
|
|
248
307
|
// after_tool_call -> track CLI outcomes + send tool_result step to AgentSession
|
|
249
308
|
api.on('after_tool_call', async (event, ctx) => {
|
|
309
|
+
if (ctx.sessionKey) endToolRenewal(ctx.sessionKey);
|
|
250
310
|
if (ctx.sessionKey && event.toolCallId && pendingSendCalls.delete(event.toolCallId)) {
|
|
251
311
|
recordMessageSend(ctx.sessionKey, !event.error);
|
|
252
312
|
}
|
package/src/runtime.ts
CHANGED
|
@@ -32,6 +32,23 @@ export type ParallAccountState = {
|
|
|
32
32
|
wikiMountRoot?: string;
|
|
33
33
|
ws?: ParallWs;
|
|
34
34
|
orchestratorSessionKey?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Per-lane dispatch context dir (PRLL_CONTEXT_DIR contract) — set when the
|
|
37
|
+
* gateway runs the dispatch ledger; hooks inject it into exec env so the
|
|
38
|
+
* CLI binds replies to their dispatch lane.
|
|
39
|
+
*/
|
|
40
|
+
dispatchContextDir?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Per-session dispatch context file resolver (PRLL_CONTEXT_FILE contract)
|
|
43
|
+
* — the CLI's typed dispatch binding (task_update effects) reads from it.
|
|
44
|
+
*/
|
|
45
|
+
contextFilePathForSession?: (sessionKey: string) => string;
|
|
46
|
+
/**
|
|
47
|
+
* Lease-renewal bridge into the gateway: openclaw tool activity flows
|
|
48
|
+
* through hooks (not the RuntimeEvent stream), so hooks must forward it or
|
|
49
|
+
* a long exec outlives the lane lease.
|
|
50
|
+
*/
|
|
51
|
+
touchRuntimeActivity?: (sessionKey: string) => void;
|
|
35
52
|
[key: string]: unknown;
|
|
36
53
|
};
|
|
37
54
|
|