@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/gateway.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gateway.d.ts","sourceRoot":"","sources":["../src/gateway.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAE9D,uGAAuG;AACvG,KAAK,qBAAqB,CAAC,CAAC,GAAG,OAAO,IAAI,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AACnF,OAAO,
|
|
1
|
+
{"version":3,"file":"gateway.d.ts","sourceRoot":"","sources":["../src/gateway.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAE9D,uGAAuG;AACvG,KAAK,qBAAqB,CAAC,CAAC,GAAG,OAAO,IAAI,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AACnF,OAAO,EASL,KAAK,eAAe,EAGrB,MAAM,oBAAoB,CAAC;AAqB5B,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AA2KxD,wBAAgB,6BAA6B,CAAC,IAAI,EAAE;IAClD,IAAI,EAAE,aAAa,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,eAAe,CA0KlB;AAED,eAAO,MAAM,aAAa,EAAE,qBAAqB,CAAC,qBAAqB,CAqLtE,CAAC"}
|
package/dist/gateway.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ParallAgentGateway, capabilityBinDir, parseShutdownDeadlineMs, parseForkDeadlineMs, parseDispatchDeadlineMs, initAgentTelemetry, createOtelLogger, } from '@parall/agent-core';
|
|
1
|
+
import { ParallAgentGateway, capabilityBinDir, dispatchLaneContextDir, parseShutdownDeadlineMs, parseForkDeadlineMs, parseDispatchDeadlineMs, initAgentTelemetry, createOtelLogger, } from '@parall/agent-core';
|
|
2
2
|
import { appendPreparedLocalAttachmentRefs, ensureLocalAttachmentGitExclude, pinLocalAttachmentPaths, } from '@parall/agent-core/internal/attachment-input';
|
|
3
3
|
import { ApiError, ParallClient, ParallWs } from '@parall/sdk';
|
|
4
4
|
import * as crypto from 'node:crypto';
|
|
@@ -11,6 +11,15 @@ import { fetchAndApplyPlatformConfig, getChannelCapabilityKeys } from './config-
|
|
|
11
11
|
import { startWikiHelper } from './wiki-helper.js';
|
|
12
12
|
import { SessionManager } from './oc-session.js';
|
|
13
13
|
import { cleanupForkSession, clearSessionState, forkOrchestratorSession, resolveSessionId, resolveTranscriptFile, } from './fork.js';
|
|
14
|
+
/**
|
|
15
|
+
* Per-session dispatch context file (PRLL_CONTEXT_FILE contract) — same
|
|
16
|
+
* encoding as the claude/codex bridges: base64url(sessionKey) under the
|
|
17
|
+
* state dir's dispatch-context/.
|
|
18
|
+
*/
|
|
19
|
+
function sessionContextFilePath(stateDir, sessionKey) {
|
|
20
|
+
const fileName = Buffer.from(sessionKey).toString('base64url');
|
|
21
|
+
return path.join(stateDir, 'dispatch-context', `${fileName}.json`);
|
|
22
|
+
}
|
|
14
23
|
function resolveWsUrl(account) {
|
|
15
24
|
if (account.config.ws_url)
|
|
16
25
|
return account.config.ws_url;
|
|
@@ -404,6 +413,18 @@ export const parallGateway = {
|
|
|
404
413
|
runtimeKey: orchestratorKey,
|
|
405
414
|
runtimeRef: { hostname: os.hostname(), pid: process.pid },
|
|
406
415
|
dispatchAdapter,
|
|
416
|
+
// Opts openclaw into the dispatch ledger (claim/fold/complete +
|
|
417
|
+
// idempotent reply effects) — the same shared-gateway machinery
|
|
418
|
+
// claude/codex ride; openclaw stays buffer-only (no mid-turn steer),
|
|
419
|
+
// which the ledger does not require. Replies already flow through
|
|
420
|
+
// @parall/cli, which reads PRLL_CONTEXT_DIR (injected in hooks.ts)
|
|
421
|
+
// to bind dispatch_lane + reply effect keys.
|
|
422
|
+
// Design: docs/engineering-design/dispatch-convergence-design.md §7 (S2).
|
|
423
|
+
dispatchContextDir: dispatchLaneContextDir(stateDir),
|
|
424
|
+
// Per-session context file (PRLL_CONTEXT_FILE contract) — the CLI's
|
|
425
|
+
// TYPED dispatch binding (parall tasks update → task_update effect)
|
|
426
|
+
// reads lane/event/task fields from this file, not the lane dir.
|
|
427
|
+
contextFilePathForSession: (sessionKey) => sessionContextFilePath(stateDir, sessionKey),
|
|
407
428
|
log: otelLog,
|
|
408
429
|
// Live capability view for hint routing: the channel reply hint
|
|
409
430
|
// points at the vendor CLI only while the grant is active.
|
|
@@ -428,6 +449,12 @@ export const parallGateway = {
|
|
|
428
449
|
wikiMountRoot,
|
|
429
450
|
ws,
|
|
430
451
|
orchestratorSessionKey: orchestratorKey,
|
|
452
|
+
dispatchContextDir: dispatchLaneContextDir(stateDir),
|
|
453
|
+
contextFilePathForSession: (sessionKey) => sessionContextFilePath(stateDir, sessionKey),
|
|
454
|
+
// Lease-renewal bridge: openclaw tool calls flow through hooks,
|
|
455
|
+
// not the RuntimeEvent stream, so hook activity must renew the
|
|
456
|
+
// ledger lanes or a long exec outlives the lease (STALE_LANE).
|
|
457
|
+
touchRuntimeActivity: (sessionKey) => gateway.touchRuntimeActivity(sessionKey),
|
|
431
458
|
});
|
|
432
459
|
},
|
|
433
460
|
onSessionBinding: async ({ sessionKey, agentSessionId }) => {
|
package/dist/hooks.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAgH7D,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,iBAAiB,
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAgH7D,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,iBAAiB,QA+OzD"}
|
package/dist/hooks.js
CHANGED
|
@@ -118,6 +118,45 @@ export function registerParallHooks(api) {
|
|
|
118
118
|
};
|
|
119
119
|
});
|
|
120
120
|
const pendingSendCalls = new Map();
|
|
121
|
+
// Lane lease keepalive across the tool-call lifecycle. OpenClaw tool calls
|
|
122
|
+
// bypass the RuntimeEvent stream, so lane renewal must ride these hooks —
|
|
123
|
+
// and a ONE-SHOT touch at tool start is not enough: a single exec running
|
|
124
|
+
// past the lane TTL (10min server-side) would still be dethroned mid-call
|
|
125
|
+
// and the eventual CLI reply would die with STALE_LANE. While any tool call
|
|
126
|
+
// is in flight for a session, an unref'd interval keeps touching; the
|
|
127
|
+
// half-TTL throttle in the ledger decides when a real heartbeat is sent.
|
|
128
|
+
const laneRenewals = new Map();
|
|
129
|
+
const LANE_RENEW_INTERVAL_MS = 180_000;
|
|
130
|
+
const beginToolRenewal = (sessionKey) => {
|
|
131
|
+
const accountId = extractAccountIdFromSessionKey(sessionKey);
|
|
132
|
+
const state = accountId ? getParallAccountState(accountId) : undefined;
|
|
133
|
+
if (!state?.touchRuntimeActivity)
|
|
134
|
+
return;
|
|
135
|
+
state.touchRuntimeActivity(sessionKey);
|
|
136
|
+
const entry = laneRenewals.get(sessionKey) ?? { count: 0 };
|
|
137
|
+
entry.count++;
|
|
138
|
+
if (!entry.timer) {
|
|
139
|
+
entry.timer = setInterval(() => state.touchRuntimeActivity?.(sessionKey), LANE_RENEW_INTERVAL_MS);
|
|
140
|
+
entry.timer.unref?.();
|
|
141
|
+
}
|
|
142
|
+
laneRenewals.set(sessionKey, entry);
|
|
143
|
+
};
|
|
144
|
+
const endToolRenewal = (sessionKey) => {
|
|
145
|
+
const entry = laneRenewals.get(sessionKey);
|
|
146
|
+
if (entry) {
|
|
147
|
+
entry.count--;
|
|
148
|
+
if (entry.count <= 0) {
|
|
149
|
+
if (entry.timer)
|
|
150
|
+
clearInterval(entry.timer);
|
|
151
|
+
laneRenewals.delete(sessionKey);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
const accountId = extractAccountIdFromSessionKey(sessionKey);
|
|
155
|
+
const state = accountId ? getParallAccountState(accountId) : undefined;
|
|
156
|
+
// Final touch on completion — covers the reply window right after a
|
|
157
|
+
// long tool call ends.
|
|
158
|
+
state?.touchRuntimeActivity?.(sessionKey);
|
|
159
|
+
};
|
|
121
160
|
// before_tool_call -> (1) update dispatch metrics, (2) await step creation, (3) ENV injection
|
|
122
161
|
// OpenClaw tool calls bypass the RuntimeEvent stream (they go through hooks, not the
|
|
123
162
|
// gateway-base for-await loop), so dispatch metrics must be updated here as well.
|
|
@@ -125,6 +164,9 @@ export function registerParallHooks(api) {
|
|
|
125
164
|
const sessionKey = ctx.sessionKey;
|
|
126
165
|
if (sessionKey) {
|
|
127
166
|
recordToolCall(sessionKey);
|
|
167
|
+
// Every tool (not just exec) keeps the ledger lane alive for its
|
|
168
|
+
// whole lifetime — see laneRenewals above.
|
|
169
|
+
beginToolRenewal(sessionKey);
|
|
128
170
|
if (event.toolName === 'exec' && event.toolCallId) {
|
|
129
171
|
const command = event.params?.command;
|
|
130
172
|
if (isParallSendCommand(command)) {
|
|
@@ -209,6 +251,20 @@ export function registerParallHooks(api) {
|
|
|
209
251
|
injectedEnv.PRLL_TRIGGER_MESSAGE_ID = triggerMsgId;
|
|
210
252
|
if (state.wikiMountRoot)
|
|
211
253
|
injectedEnv.PRLL_WIKI_MOUNT_ROOT = state.wikiMountRoot;
|
|
254
|
+
// Dispatch-ledger contract: the CLI keys into this directory by send
|
|
255
|
+
// target to bind dispatch_lane + the reply:<dsp> effect key (idempotent
|
|
256
|
+
// replies). Set only when the gateway runs the ledger.
|
|
257
|
+
if (state.dispatchContextDir)
|
|
258
|
+
injectedEnv.PRLL_CONTEXT_DIR = state.dispatchContextDir;
|
|
259
|
+
// Per-session context file — the CLI's TYPED binding (parall tasks
|
|
260
|
+
// update → task_update:<dsp> effect) reads lane/event/task from here.
|
|
261
|
+
if (state.contextFilePathForSession) {
|
|
262
|
+
injectedEnv.PRLL_CONTEXT_FILE = state.contextFilePathForSession(sessionKey);
|
|
263
|
+
}
|
|
264
|
+
// Long tool calls bypass the RuntimeEvent stream — forward activity so
|
|
265
|
+
// the ledger lane lease renews (a >TTL exec would otherwise be dethroned
|
|
266
|
+
// mid-turn and the eventual CLI reply would die with STALE_LANE).
|
|
267
|
+
state.touchRuntimeActivity?.(sessionKey);
|
|
212
268
|
// OpenClaw context (upstream doesn't inject these into exec env yet)
|
|
213
269
|
injectedEnv.OPENCLAW_SESSION_KEY = sessionKey;
|
|
214
270
|
if (event.toolCallId)
|
|
@@ -223,6 +279,8 @@ export function registerParallHooks(api) {
|
|
|
223
279
|
});
|
|
224
280
|
// after_tool_call -> track CLI outcomes + send tool_result step to AgentSession
|
|
225
281
|
api.on('after_tool_call', async (event, ctx) => {
|
|
282
|
+
if (ctx.sessionKey)
|
|
283
|
+
endToolRenewal(ctx.sessionKey);
|
|
226
284
|
if (ctx.sessionKey && event.toolCallId && pendingSendCalls.delete(event.toolCallId)) {
|
|
227
285
|
recordMessageSend(ctx.sessionKey, !event.error);
|
|
228
286
|
}
|