c8ctl-plugin-nano 1.62.1 → 1.62.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/agent-instance.mjs +35 -3
- package/package.json +8 -8
package/agent-instance.mjs
CHANGED
|
@@ -311,6 +311,23 @@ function shortHash(text) {
|
|
|
311
311
|
return (h >>> 0).toString(36);
|
|
312
312
|
}
|
|
313
313
|
|
|
314
|
+
// #247: the per-ACTIVATION namespace folded into every content-derived historyItemId
|
|
315
|
+
// so a resumed harness (which restarts its ACP message / tool-call numbering) does not
|
|
316
|
+
// collide with — and get silently deduplicated against — the prior activation's turns.
|
|
317
|
+
// The activation identity is the lease token (a fresh token per `activate jobs`), else
|
|
318
|
+
// the jobKey, else the elementInstanceKey. It is HASHED — the lease token is a
|
|
319
|
+
// secret-ish fence token that must never be embedded raw in a persisted id — and stays
|
|
320
|
+
// STABLE for the life of one activation, so an at-least-once redelivery still dedups
|
|
321
|
+
// within the activation while a genuine resume (new lease) gets a distinct namespace.
|
|
322
|
+
// Returns '' when no identity is available, leaving the id un-namespaced (unchanged).
|
|
323
|
+
export function activationNamespace(job = {}) {
|
|
324
|
+
const leaseToken = job?.leaseToken != null ? String(job.leaseToken) : '';
|
|
325
|
+
const jobKey = job?.jobKey != null ? String(job.jobKey) : '';
|
|
326
|
+
const elementInstanceKey = job?.elementInstanceKey != null ? String(job.elementInstanceKey) : '';
|
|
327
|
+
const token = leaseToken || jobKey || elementInstanceKey || '';
|
|
328
|
+
return token ? shortHash(token) : '';
|
|
329
|
+
}
|
|
330
|
+
|
|
314
331
|
// Extract per-call metrics from an ACP update when the agent carries them (many
|
|
315
332
|
// ACP agents do not — a documented ACP fidelity gap — so this is usually absent).
|
|
316
333
|
// Reads the common usage locations and maps to the AgentHistory item metric field
|
|
@@ -408,6 +425,21 @@ export function createAgentInstanceProducer(opts = {}) {
|
|
|
408
425
|
const elementInstanceKey = job?.elementInstanceKey != null ? String(job.elementInstanceKey) : '';
|
|
409
426
|
const elementId = job?.elementId != null ? String(job.elementId) : null;
|
|
410
427
|
const processInstanceKey = job?.processInstanceKey != null ? String(job.processInstanceKey) : '';
|
|
428
|
+
// #247: namespace every content-derived historyItemId per ACTIVATION. When a parked
|
|
429
|
+
// process resumes, a fresh (cold-started) harness re-activates the SAME AgentInstance
|
|
430
|
+
// and generally RESTARTS its ACP message / tool-call numbering (m-1, call-1, …). The
|
|
431
|
+
// engine dedups appends by historyItemId, so without a per-activation namespace those
|
|
432
|
+
// continuation turns collide with the PRIOR activation's ids and are silently dropped
|
|
433
|
+
// as stale history — the transcript never advances, and the next reactivation replays
|
|
434
|
+
// the same side effects (the failure mode #239 exists to prevent). The namespace is
|
|
435
|
+
// derived from the job's ACTIVATION identity (see `activationNamespace`): stable for
|
|
436
|
+
// the life of this producer, so an at-least-once redelivery of the SAME activation
|
|
437
|
+
// still dedups correctly, while a genuine resume (new lease → new namespace) appends
|
|
438
|
+
// instead of colliding. The CONFIGURATION turn is left keyed on the elementInstanceKey
|
|
439
|
+
// ALONE (stable across activations) so its single header dedups per instance rather
|
|
440
|
+
// than duplicating on every resume.
|
|
441
|
+
const activationNs = activationNamespace(job);
|
|
442
|
+
const nsHistoryId = (id) => (activationNs ? `${activationNs}:${id}` : id);
|
|
411
443
|
// #229 cross-channel correlation, compact form. Stamps job/eik/pik so the
|
|
412
444
|
// AgentInstance channel can be joined to the job / relay / git channels. This is the
|
|
413
445
|
// terse rendering used by the observability lines; `correlation()` below is the
|
|
@@ -637,7 +669,7 @@ export function createAgentInstanceProducer(opts = {}) {
|
|
|
637
669
|
if (!hasText && !hasMetrics) return;
|
|
638
670
|
const idBasis = isNonBlank(msg.messageId) ? String(msg.messageId) : `h:${shortHash(text)}`;
|
|
639
671
|
const turn = {
|
|
640
|
-
historyItemId: `${msg.role.toLowerCase()}:${idBasis}
|
|
672
|
+
historyItemId: nsHistoryId(`${msg.role.toLowerCase()}:${idBasis}`),
|
|
641
673
|
loopIteration: msg.loopIteration,
|
|
642
674
|
role: msg.role,
|
|
643
675
|
content: hasText ? [{ contentType: 'TEXT', text }] : [],
|
|
@@ -653,7 +685,7 @@ export function createAgentInstanceProducer(opts = {}) {
|
|
|
653
685
|
flushMessage();
|
|
654
686
|
if (isNonBlank(c.name)) toolNames.set(String(c.callId), String(c.name));
|
|
655
687
|
const turn = {
|
|
656
|
-
historyItemId: `toolcall:${c.callId}
|
|
688
|
+
historyItemId: nsHistoryId(`toolcall:${c.callId}`),
|
|
657
689
|
loopIteration,
|
|
658
690
|
role: 'ASSISTANT',
|
|
659
691
|
content: [],
|
|
@@ -673,7 +705,7 @@ export function createAgentInstanceProducer(opts = {}) {
|
|
|
673
705
|
const onToolResult = (c) => {
|
|
674
706
|
flushMessage();
|
|
675
707
|
const turn = {
|
|
676
|
-
historyItemId: `toolresult:${c.callId}
|
|
708
|
+
historyItemId: nsHistoryId(`toolresult:${c.callId}`),
|
|
677
709
|
loopIteration,
|
|
678
710
|
role: 'TOOL_RESULT',
|
|
679
711
|
content: contentForResult(c.result),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "c8ctl-plugin-nano",
|
|
3
|
-
"version": "1.62.
|
|
3
|
+
"version": "1.62.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "c8ctl plugin to start, inspect, and stop a local Nano BPM (nanobpmn) cluster",
|
|
6
6
|
"main": "c8ctl-plugin.js",
|
|
@@ -74,12 +74,12 @@
|
|
|
74
74
|
},
|
|
75
75
|
"optionalDependencies": {
|
|
76
76
|
"node-pty": "^1.0.0",
|
|
77
|
-
"@nanobpm/c8ctl-plugin-nano-darwin-arm64": "1.62.
|
|
78
|
-
"@nanobpm/c8ctl-plugin-nano-darwin-x64": "1.62.
|
|
79
|
-
"@nanobpm/c8ctl-plugin-nano-linux-x64": "1.62.
|
|
80
|
-
"@nanobpm/c8ctl-plugin-nano-linux-arm64": "1.62.
|
|
81
|
-
"@nanobpm/c8ctl-plugin-nano-linux-armv7": "1.62.
|
|
82
|
-
"@nanobpm/c8ctl-plugin-nano-linux-armv6": "1.62.
|
|
83
|
-
"@nanobpm/c8ctl-plugin-nano-win32-x64": "1.62.
|
|
77
|
+
"@nanobpm/c8ctl-plugin-nano-darwin-arm64": "1.62.2",
|
|
78
|
+
"@nanobpm/c8ctl-plugin-nano-darwin-x64": "1.62.2",
|
|
79
|
+
"@nanobpm/c8ctl-plugin-nano-linux-x64": "1.62.2",
|
|
80
|
+
"@nanobpm/c8ctl-plugin-nano-linux-arm64": "1.62.2",
|
|
81
|
+
"@nanobpm/c8ctl-plugin-nano-linux-armv7": "1.62.2",
|
|
82
|
+
"@nanobpm/c8ctl-plugin-nano-linux-armv6": "1.62.2",
|
|
83
|
+
"@nanobpm/c8ctl-plugin-nano-win32-x64": "1.62.2"
|
|
84
84
|
}
|
|
85
85
|
}
|