@stigmer/runner 3.12.6 → 3.12.8
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/.build-fingerprint +1 -1
- package/dist/activities/call-agent-status.d.ts +14 -2
- package/dist/activities/call-agent-status.js +24 -7
- package/dist/activities/call-agent-status.js.map +1 -1
- package/dist/activities/execute-cursor/index.d.ts +10 -0
- package/dist/activities/execute-cursor/index.js +26 -0
- package/dist/activities/execute-cursor/index.js.map +1 -1
- package/dist/activities/execute-cursor/prompt-builder.d.ts +12 -0
- package/dist/activities/execute-cursor/prompt-builder.js +11 -0
- package/dist/activities/execute-cursor/prompt-builder.js.map +1 -1
- package/dist/activities/execute-deep-agent/mcp-gate.d.ts +2 -0
- package/dist/activities/execute-deep-agent/mcp-gate.js +2 -1
- package/dist/activities/execute-deep-agent/mcp-gate.js.map +1 -1
- package/dist/activities/execute-deep-agent/prompt-builder.d.ts +9 -0
- package/dist/activities/execute-deep-agent/prompt-builder.js +10 -0
- package/dist/activities/execute-deep-agent/prompt-builder.js.map +1 -1
- package/dist/activities/execute-deep-agent/setup.js +27 -0
- package/dist/activities/execute-deep-agent/setup.js.map +1 -1
- package/dist/config.d.ts +10 -0
- package/dist/config.js +3 -0
- package/dist/config.js.map +1 -1
- package/dist/main.js +3 -0
- package/dist/main.js.map +1 -1
- package/dist/runner-manager.d.ts +2 -0
- package/dist/runner-manager.js +1 -0
- package/dist/runner-manager.js.map +1 -1
- package/dist/runner.d.ts +2 -0
- package/dist/runner.js +33 -6
- package/dist/runner.js.map +1 -1
- package/dist/shared/artifact-storage.js +7 -4
- package/dist/shared/artifact-storage.js.map +1 -1
- package/dist/shared/memory-attachment.d.ts +97 -0
- package/dist/shared/memory-attachment.js +136 -0
- package/dist/shared/memory-attachment.js.map +1 -0
- package/dist/shared/recalled-memories.d.ts +55 -0
- package/dist/shared/recalled-memories.js +70 -0
- package/dist/shared/recalled-memories.js.map +1 -0
- package/dist/shared/tool-kind.js +9 -0
- package/dist/shared/tool-kind.js.map +1 -1
- package/dist/workflows/call-agent-orchestrator.d.ts +14 -2
- package/dist/workflows/call-agent-orchestrator.js +55 -18
- package/dist/workflows/call-agent-orchestrator.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/golden-e2e.test.ts +1 -1
- package/src/activities/__tests__/call-agent-status.test.ts +30 -5
- package/src/activities/__tests__/classify-tool-approvals.test.ts +1 -0
- package/src/activities/__tests__/discover-mcp-server.test.ts +1 -0
- package/src/activities/call-agent-status.ts +25 -8
- package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +79 -0
- package/src/activities/execute-cursor/index.ts +43 -0
- package/src/activities/execute-cursor/prompt-builder.ts +28 -0
- package/src/activities/execute-deep-agent/__tests__/hitl-reject.test.ts +1 -0
- package/src/activities/execute-deep-agent/__tests__/hitl-resume-approve-all.test.ts +1 -0
- package/src/activities/execute-deep-agent/__tests__/hitl-resume-history.test.ts +1 -0
- package/src/activities/execute-deep-agent/__tests__/index.test.ts +1 -0
- package/src/activities/execute-deep-agent/__tests__/mcp-gate.test.ts +7 -0
- package/src/activities/execute-deep-agent/__tests__/prompt-builder.test.ts +48 -0
- package/src/activities/execute-deep-agent/__tests__/sequential-gate-resume.test.ts +1 -0
- package/src/activities/execute-deep-agent/mcp-gate.ts +4 -1
- package/src/activities/execute-deep-agent/prompt-builder.ts +22 -0
- package/src/activities/execute-deep-agent/setup.ts +40 -0
- package/src/config.ts +13 -0
- package/src/main.ts +3 -0
- package/src/runner-manager.ts +5 -0
- package/src/runner.ts +42 -6
- package/src/shared/__tests__/artifact-storage.test.ts +21 -0
- package/src/shared/__tests__/memory-attachment.test.ts +167 -0
- package/src/shared/__tests__/recalled-memories.test.ts +88 -0
- package/src/shared/artifact-storage.ts +9 -4
- package/src/shared/memory-attachment.ts +167 -0
- package/src/shared/recalled-memories.ts +90 -0
- package/src/shared/tool-kind.ts +10 -0
- package/src/workflows/call-agent-orchestrator.ts +60 -24
|
@@ -16,8 +16,20 @@
|
|
|
16
16
|
* and pure logic. No Node.js built-ins.
|
|
17
17
|
*/
|
|
18
18
|
import type { AgentCallConfig, AgentCallResult } from "../workflow-engine/types.js";
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Identity-only "go look" trigger (DD-012, stigmer-cloud#509): the child's
|
|
21
|
+
* server signals just the gated child's execution id, and this workflow
|
|
22
|
+
* derives the gate from the child's persisted record. The payload MUST stay a
|
|
23
|
+
* bare string: it crosses the polyglot boundary from the Java server, whose
|
|
24
|
+
* client serializes proto messages as `json/protobuf` — an encoding this
|
|
25
|
+
* worker's default converter cannot decode, which poisoned the workflow task
|
|
26
|
+
* in a permanent retry loop (the original cloud#509 failure). The object
|
|
27
|
+
* shape is tolerated for a future Go sender's natural `{executionId}` JSON,
|
|
28
|
+
* mirroring child_execution_started's both-shapes handling below.
|
|
29
|
+
*/
|
|
30
|
+
export declare const childApprovalRequired: import("@temporalio/workflow").SignalDefinition<[string | {
|
|
31
|
+
executionId?: string;
|
|
32
|
+
}], string>;
|
|
21
33
|
/** Sent by the platform immediately after the child AgentExecution starts. */
|
|
22
34
|
export declare const childExecutionStarted: import("@temporalio/workflow").SignalDefinition<[{
|
|
23
35
|
executionId: string;
|
|
@@ -20,6 +20,17 @@ import { AgentCallError } from "../workflow-engine/types.js";
|
|
|
20
20
|
// ─────────────────────────────────────────────────────────────────────
|
|
21
21
|
// Signal Definitions
|
|
22
22
|
// ─────────────────────────────────────────────────────────────────────
|
|
23
|
+
/**
|
|
24
|
+
* Identity-only "go look" trigger (DD-012, stigmer-cloud#509): the child's
|
|
25
|
+
* server signals just the gated child's execution id, and this workflow
|
|
26
|
+
* derives the gate from the child's persisted record. The payload MUST stay a
|
|
27
|
+
* bare string: it crosses the polyglot boundary from the Java server, whose
|
|
28
|
+
* client serializes proto messages as `json/protobuf` — an encoding this
|
|
29
|
+
* worker's default converter cannot decode, which poisoned the workflow task
|
|
30
|
+
* in a permanent retry loop (the original cloud#509 failure). The object
|
|
31
|
+
* shape is tolerated for a future Go sender's natural `{executionId}` JSON,
|
|
32
|
+
* mirroring child_execution_started's both-shapes handling below.
|
|
33
|
+
*/
|
|
23
34
|
export const childApprovalRequired = defineSignal("child_approval_required");
|
|
24
35
|
/** Sent by the platform immediately after the child AgentExecution starts. */
|
|
25
36
|
export const childExecutionStarted = defineSignal("child_execution_started");
|
|
@@ -61,14 +72,26 @@ export async function orchestrateAgentCall(input) {
|
|
|
61
72
|
let activityDone = false;
|
|
62
73
|
let activityResult = {};
|
|
63
74
|
let activityError = undefined;
|
|
64
|
-
|
|
75
|
+
// Child ids whose approval gates await derivation. A set (not a flag)
|
|
76
|
+
// because one workflow has ONE live handler per signal name: with parallel
|
|
77
|
+
// agent_call tasks, whichever orchestration registered last receives every
|
|
78
|
+
// child's signal, and each gate must be derived under its OWN child id for
|
|
79
|
+
// the per-child status merge to file it correctly.
|
|
80
|
+
const pendingApprovalChildIds = new Set();
|
|
65
81
|
let childExecId;
|
|
66
82
|
let initialProgressEmitted = false;
|
|
67
|
-
setHandler(childApprovalRequired, (
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
83
|
+
setHandler(childApprovalRequired, (payload) => {
|
|
84
|
+
// Identity-only signal (see the definition above): note the child and
|
|
85
|
+
// mark its gate for derivation in the main loop — approval details never
|
|
86
|
+
// travel through the signal itself.
|
|
87
|
+
const signaledId = typeof payload === "string" ? payload : payload?.executionId;
|
|
88
|
+
if (!signaledId) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (!childExecId) {
|
|
92
|
+
childExecId = signaledId;
|
|
71
93
|
}
|
|
94
|
+
pendingApprovalChildIds.add(signaledId);
|
|
72
95
|
});
|
|
73
96
|
setHandler(childExecutionStarted, (payload) => {
|
|
74
97
|
// The Go server sends { executionId: "aex_xxx" } (struct with json tag).
|
|
@@ -159,7 +182,7 @@ export async function orchestrateAgentCall(input) {
|
|
|
159
182
|
while (!activityDone) {
|
|
160
183
|
// Wait for a signal, activity completion, or periodic timeout for progress polling.
|
|
161
184
|
// condition() returns false on timeout, true when the predicate became true.
|
|
162
|
-
const conditionMet = await condition(() => activityDone ||
|
|
185
|
+
const conditionMet = await condition(() => activityDone || pendingApprovalChildIds.size > 0 || (!!childExecId && !initialProgressEmitted), PROGRESS_POLL_INTERVAL);
|
|
163
186
|
if (activityDone)
|
|
164
187
|
break;
|
|
165
188
|
// Emit initial progress with childExecutionId as soon as it's known
|
|
@@ -185,18 +208,32 @@ export async function orchestrateAgentCall(input) {
|
|
|
185
208
|
}
|
|
186
209
|
await syncFileReviews(childExecId);
|
|
187
210
|
}
|
|
188
|
-
// Handle HITL approval
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
211
|
+
// Handle HITL approval notifications: derive each signaled child's gate
|
|
212
|
+
// from its persisted record (identity-only signal, DD-012). The child's
|
|
213
|
+
// server persists the gate BEFORE signaling, so an empty derivation means
|
|
214
|
+
// the gate already resolved — the activity answers false and there is
|
|
215
|
+
// deliberately no retry (see updateWorkflowTaskApprovalStatus).
|
|
216
|
+
if (pendingApprovalChildIds.size > 0) {
|
|
217
|
+
// Drain a deterministic snapshot: insertion order is replay-stable, and
|
|
218
|
+
// ids signaled during the awaits below land in the set for the next pass.
|
|
219
|
+
const toDerive = [...pendingApprovalChildIds];
|
|
220
|
+
pendingApprovalChildIds.clear();
|
|
221
|
+
for (const signaledChildId of toDerive) {
|
|
222
|
+
try {
|
|
223
|
+
const surfaced = await statusProxy.UpdateWorkflowTaskApprovalStatus(input.workflowExecutionId, input.taskName, signaledChildId);
|
|
224
|
+
if (!surfaced) {
|
|
225
|
+
log.info("Child approval gate already resolved before derivation; nothing surfaced", {
|
|
226
|
+
taskName: input.taskName,
|
|
227
|
+
childExecId: signaledChildId,
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
catch (statusErr) {
|
|
232
|
+
log.warn("Failed to update workflow approval status (non-fatal)", {
|
|
233
|
+
error: String(statusErr),
|
|
234
|
+
taskName: input.taskName,
|
|
235
|
+
});
|
|
236
|
+
}
|
|
200
237
|
}
|
|
201
238
|
}
|
|
202
239
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"call-agent-orchestrator.js","sourceRoot":"","sources":["../../src/workflows/call-agent-orchestrator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EACL,YAAY,EACZ,UAAU,EACV,SAAS,EACT,eAAe,EACf,oBAAoB,EACpB,GAAG,EAEH,cAAc,GACf,MAAM,sBAAsB,CAAC;AAM9B,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"call-agent-orchestrator.js","sourceRoot":"","sources":["../../src/workflows/call-agent-orchestrator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EACL,YAAY,EACZ,UAAU,EACV,SAAS,EACT,eAAe,EACf,oBAAoB,EACpB,GAAG,EAEH,cAAc,GACf,MAAM,sBAAsB,CAAC;AAM9B,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAE7D,wEAAwE;AACxE,qBAAqB;AACrB,wEAAwE;AAExE;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,YAAY,CAC/C,yBAAyB,CAC1B,CAAC;AAEF,8EAA8E;AAC9E,MAAM,CAAC,MAAM,qBAAqB,GAAG,YAAY,CAC/C,yBAAyB,CAC1B,CAAC;AAUF,yEAAyE;AACzE,0EAA0E;AAC1E,0EAA0E;AAC1E,qEAAqE;AACrE,0BAA0B;AAC1B,MAAM,UAAU,GAAG,eAAe,CAAkB;IAClD,mBAAmB,EAAE,IAAI;IACzB,KAAK,EAAE;QACL,eAAe,EAAE,CAAC;KACnB;CACF,CAAC,CAAC;AAEH,MAAM,WAAW,GAAG,oBAAoB,CAAmB;IACzD,mBAAmB,EAAE,KAAK;IAC1B,KAAK,EAAE;QACL,eAAe,EAAE,CAAC;QAClB,eAAe,EAAE,IAAI;QACrB,kBAAkB,EAAE,CAAC;KACtB;CACF,CAAC,CAAC;AAEH,MAAM,UAAU,GAAG,oBAAoB,CAAkB;IACvD,mBAAmB,EAAE,KAAK;IAC1B,KAAK,EAAE;QACL,eAAe,EAAE,CAAC;QAClB,eAAe,EAAE,OAAO;KACzB;CACF,CAAC,CAAC;AAuBH;;;;;;GAMG;AACH,MAAM,sBAAsB,GAAG,KAAK,CAAC;AAErC,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,KAAkC;IAElC,IAAI,YAAY,GAAG,KAAK,CAAC;IACzB,IAAI,cAAc,GAAoB,EAAE,CAAC;IACzC,IAAI,aAAa,GAAY,SAAS,CAAC;IACvC,sEAAsE;IACtE,2EAA2E;IAC3E,2EAA2E;IAC3E,2EAA2E;IAC3E,mDAAmD;IACnD,MAAM,uBAAuB,GAAG,IAAI,GAAG,EAAU,CAAC;IAClD,IAAI,WAA+B,CAAC;IACpC,IAAI,sBAAsB,GAAG,KAAK,CAAC;IAEnC,UAAU,CAAC,qBAAqB,EAAE,CAAC,OAA0C,EAAE,EAAE;QAC/E,sEAAsE;QACtE,yEAAyE;QACzE,oCAAoC;QACpC,MAAM,UAAU,GAAG,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE,WAAW,CAAC;QAChF,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO;QACT,CAAC;QACD,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,WAAW,GAAG,UAAU,CAAC;QAC3B,CAAC;QACD,uBAAuB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,UAAU,CAAC,qBAAqB,EAAE,CAAC,OAAyC,EAAE,EAAE;QAC9E,yEAAyE;QACzE,iFAAiF;QACjF,0DAA0D;QAC1D,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;YAChC,WAAW,GAAG,OAAO,CAAC;QACxB,CAAC;aAAM,IAAI,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,aAAa,IAAI,OAAO,EAAE,CAAC;YAC9E,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;QACpC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,cAAc,GAAG;QACrB,GAAG,KAAK,CAAC,MAAM;QACf,UAAU,EAAE,KAAK,CAAC,QAAQ;QAC1B,UAAU,EAAE,KAAK,CAAC,mBAAmB;KACtC,CAAC;IAEF,GAAG,CAAC,IAAI,CAAC,8CAA8C,EAAE;QACvD,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,SAAS,EAAE,cAAc,CAAC,MAAM,KAAK,SAAS;QAC9C,eAAe,EAAE,cAAc,CAAC,MAAM,EAAE,MAAM,KAAK,SAAS;QAC5D,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;QACjD,WAAW,EAAE,CAAC,CAAC,cAAc,CAAC,UAAU;KACzC,CAAC,CAAC;IAEH,MAAM,eAAe,GAAG,UAAU;SAC/B,SAAS,CAAC,cAAc,EAAE,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,gBAAgB,CAAC;SACnE,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;QACf,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC/B,IAAI,CAAC;gBACH,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAoB,CAAC;YACzD,CAAC;YAAC,MAAM,CAAC;gBACP,cAAc,GAAG,EAAE,CAAC;YACtB,CAAC;QACH,CAAC;aAAM,CAAC;YACN,cAAc,GAAG,CAAC,MAAM,IAAI,EAAE,CAAoB,CAAC;QACrD,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,+CAA+C,EAAE;YACxD,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,aAAa,EAAE,cAAc,CAAC,UAAU,KAAK,SAAS;YACtD,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;SAClD,CAAC,CAAC;QACH,YAAY,GAAG,IAAI,CAAC;IACtB,CAAC,CAAC;SACD,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;QACb,IAAI,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,YAAY,GAAG,IAAI,CAAC;YACpB,OAAO;QACT,CAAC;QACD,aAAa,GAAG,GAAG,CAAC;QACpB,YAAY,GAAG,IAAI,CAAC;IACtB,CAAC,CAAC,CAAC;IAEL,gFAAgF;IAChF,kFAAkF;IAClF,+DAA+D;IAC/D,IAAI,iBAAqC,CAAC;IAE1C,kFAAkF;IAClF,gFAAgF;IAChF,gFAAgF;IAChF,KAAK,UAAU,eAAe,CAAC,OAAe;QAC5C,IAAI,GAAa,CAAC;QAClB,IAAI,CAAC;YACH,GAAG,GAAG,MAAM,WAAW,CAAC,iCAAiC,CAAC,OAAO,CAAC,CAAC;QACrE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,IAAI,CAAC,sDAAsD,EAAE;gBAC/D,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC;gBAClB,QAAQ,EAAE,KAAK,CAAC,QAAQ;aACzB,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QACD,yEAAyE;QACzE,MAAM,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACtC,IAAI,GAAG,KAAK,iBAAiB;YAAE,OAAO;QACtC,iBAAiB,GAAG,GAAG,CAAC;QACxB,IAAI,CAAC;YACH,MAAM,WAAW,CAAC,8BAA8B,CAAC,KAAK,CAAC,mBAAmB,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;QAC5F,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,IAAI,CAAC,0DAA0D,EAAE;gBACnE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC;gBAClB,QAAQ,EAAE,KAAK,CAAC,QAAQ;aACzB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,CAAC,YAAY,EAAE,CAAC;QACrB,oFAAoF;QACpF,6EAA6E;QAC7E,MAAM,YAAY,GAAG,MAAM,SAAS,CAClC,GAAG,EAAE,CAAC,YAAY,IAAI,uBAAuB,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,sBAAsB,CAAC,EACpG,sBAAsB,CACvB,CAAC;QAEF,IAAI,YAAY;YAAE,MAAM;QAExB,oEAAoE;QACpE,IAAI,WAAW,IAAI,CAAC,sBAAsB,EAAE,CAAC;YAC3C,sBAAsB,GAAG,IAAI,CAAC;YAC9B,MAAM,YAAY,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC;YAC7C,MAAM,eAAe,CAAC,WAAW,CAAC,CAAC;QACrC,CAAC;QAED,wEAAwE;QACxE,IAAI,CAAC,YAAY,IAAI,WAAW,EAAE,CAAC;YACjC,IAAI,QAAQ,GAAgC,IAAI,CAAC;YACjD,IAAI,CAAC;gBACH,QAAQ,GAAG,MAAM,WAAW,CAAC,yBAAyB,CAAC,WAAW,CAAC,CAAC;YACtE,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,GAAG,CAAC,IAAI,CAAC,4CAA4C,EAAE;oBACrD,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC;oBAClB,QAAQ,EAAE,KAAK,CAAC,QAAQ;iBACzB,CAAC,CAAC;YACL,CAAC;YACD,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,YAAY,CAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;YACnD,CAAC;YACD,MAAM,eAAe,CAAC,WAAW,CAAC,CAAC;QACrC,CAAC;QAED,wEAAwE;QACxE,wEAAwE;QACxE,0EAA0E;QAC1E,sEAAsE;QACtE,gEAAgE;QAChE,IAAI,uBAAuB,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;YACrC,wEAAwE;YACxE,0EAA0E;YAC1E,MAAM,QAAQ,GAAG,CAAC,GAAG,uBAAuB,CAAC,CAAC;YAC9C,uBAAuB,CAAC,KAAK,EAAE,CAAC;YAEhC,KAAK,MAAM,eAAe,IAAI,QAAQ,EAAE,CAAC;gBACvC,IAAI,CAAC;oBACH,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,gCAAgC,CACjE,KAAK,CAAC,mBAAmB,EACzB,KAAK,CAAC,QAAQ,EACd,eAAe,CAChB,CAAC;oBACF,IAAI,CAAC,QAAQ,EAAE,CAAC;wBACd,GAAG,CAAC,IAAI,CAAC,0EAA0E,EAAE;4BACnF,QAAQ,EAAE,KAAK,CAAC,QAAQ;4BACxB,WAAW,EAAE,eAAe;yBAC7B,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;gBAAC,OAAO,SAAS,EAAE,CAAC;oBACnB,GAAG,CAAC,IAAI,CAAC,uDAAuD,EAAE;wBAChE,KAAK,EAAE,MAAM,CAAC,SAAS,CAAC;wBACxB,QAAQ,EAAE,KAAK,CAAC,QAAQ;qBACzB,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,6EAA6E;IAC7E,0EAA0E;IAC1E,gFAAgF;IAChF,IAAI,WAAW,IAAI,CAAC,sBAAsB,EAAE,CAAC;QAC3C,MAAM,YAAY,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC;IAC/C,CAAC;IAED,gFAAgF;IAChF,+EAA+E;IAC/E,8CAA8C;IAC9C,IAAI,WAAW,EAAE,CAAC;QAChB,IAAI,CAAC;YACH,MAAM,WAAW,CAAC,2BAA2B,CAAC,KAAK,CAAC,mBAAmB,EAAE,WAAW,CAAC,CAAC;QACxF,CAAC;QAAC,OAAO,QAAQ,EAAE,CAAC;YAClB,GAAG,CAAC,IAAI,CAAC,sDAAsD,EAAE;gBAC/D,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC;aACxB,CAAC,CAAC;QACL,CAAC;QACD,IAAI,CAAC;YACH,MAAM,WAAW,CAAC,8BAA8B,CAAC,KAAK,CAAC,mBAAmB,EAAE,WAAW,EAAE,EAAE,CAAC,CAAC;QAC/F,CAAC;QAAC,OAAO,QAAQ,EAAE,CAAC;YAClB,GAAG,CAAC,IAAI,CAAC,yDAAyD,EAAE;gBAClE,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC;aACxB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,IAAI,aAAa,EAAE,CAAC;QAClB,IAAI,WAAW,EAAE,CAAC;YAChB,MAAM,GAAG,GAAG,aAAa,YAAY,KAAK;gBACxC,CAAC,CAAC,aAAa,CAAC,OAAO;gBACvB,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;YAC1B,MAAM,IAAI,cAAc,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QAC7C,CAAC;QACD,MAAM,aAAa,CAAC;IACtB,CAAC;IAED,mEAAmE;IACnE,8DAA8D;IAC9D,IAAI,WAAW,IAAI,CAAC,cAAc,CAAC,kBAAkB,EAAE,CAAC;QACtD,cAAc,GAAG,EAAE,GAAG,cAAc,EAAE,kBAAkB,EAAE,WAAW,EAAE,CAAC;IAC1E,CAAC;IAED,OAAO,cAAc,CAAC;AACxB,CAAC;AAED,KAAK,UAAU,YAAY,CACzB,KAAkC,EAClC,WAAmB,EACnB,QAAqC;IAErC,IAAI,CAAC;QACH,MAAM,aAAa,GAA4B;YAC7C,IAAI,EAAE,qBAAqB;YAC3B,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACpC,cAAc,EAAE,KAAK,CAAC,iBAAiB,EAAE,EAAE;YAC3C,gBAAgB,EAAE,WAAW;YAC7B,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE;YACnC,UAAU,EAAE,QAAQ,EAAE,UAAU,IAAI,CAAC;YACrC,eAAe,EAAE,QAAQ,EAAE,eAAe,IAAI,EAAE;YAChD,cAAc,EAAE,QAAQ,EAAE,cAAc,IAAI,CAAC;YAC7C,aAAa,EAAE,QAAQ,EAAE,aAAa,IAAI,CAAC;YAC3C,cAAc,EAAE,QAAQ,EAAE,cAAc,IAAI,CAAC;SAC9C,CAAC;QACF,MAAM,UAAU,CAAC,kBAAkB,CAAC,KAAK,CAAC,mBAAmB,EAAE,CAAC,aAAa,CAAC,EAAE,EAAE,CAAC,CAAC;IACtF,CAAC;IAAC,OAAO,OAAO,EAAE,CAAC;QACjB,GAAG,CAAC,IAAI,CAAC,gDAAgD,EAAE;YACzD,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC;YACtB,QAAQ,EAAE,KAAK,CAAC,QAAQ;SACzB,CAAC,CAAC;IACL,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stigmer/runner",
|
|
3
|
-
"version": "3.12.
|
|
3
|
+
"version": "3.12.8",
|
|
4
4
|
"description": "Embeddable Temporal worker for the Stigmer AI agent platform — handles agent execution, workflow orchestration, and MCP server management",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
"@opentelemetry/sdk-metrics": "^2.0.0",
|
|
95
95
|
"@opentelemetry/sdk-trace-base": "^2.0.0",
|
|
96
96
|
"@opentelemetry/sdk-trace-node": "^2.0.0",
|
|
97
|
-
"@stigmer/protos": "3.12.
|
|
97
|
+
"@stigmer/protos": "3.12.8",
|
|
98
98
|
"@temporalio/activity": "1.16.2",
|
|
99
99
|
"@temporalio/common": "1.16.2",
|
|
100
100
|
"@temporalio/interceptors-opentelemetry": "1.16.2",
|
|
@@ -76,7 +76,7 @@ function createMockActivities() {
|
|
|
76
76
|
}),
|
|
77
77
|
RunScript: async (): Promise<unknown> => ({ computed: 4 }),
|
|
78
78
|
RunShell: async (): Promise<unknown> => "hello from shell",
|
|
79
|
-
UpdateWorkflowTaskApprovalStatus: async (): Promise<
|
|
79
|
+
UpdateWorkflowTaskApprovalStatus: async (): Promise<boolean> => false,
|
|
80
80
|
ClearWorkflowApprovalStatus: async (): Promise<void> => {},
|
|
81
81
|
UpdateWorkflowFileReviewStatus: async (): Promise<void> => {},
|
|
82
82
|
GetAwaitingFileReviewChangeSetIds: async (): Promise<string[]> => [],
|
|
@@ -104,17 +104,42 @@ describe("call-agent-status file-review activities", () => {
|
|
|
104
104
|
});
|
|
105
105
|
|
|
106
106
|
describe("approval activities are scoped per-child (unify)", () => {
|
|
107
|
-
it("updateWorkflowTaskApprovalStatus scopes the write to
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
107
|
+
it("updateWorkflowTaskApprovalStatus derives the gate from the child record and scopes the write to it", async () => {
|
|
108
|
+
// Identity-only contract (DD-012, stigmer-cloud#509): the activity
|
|
109
|
+
// receives just the child id and reads the gate from the child's
|
|
110
|
+
// persisted status — the signal never carries approval details.
|
|
111
|
+
mockGetExecutionResult = {
|
|
112
|
+
status: {
|
|
113
|
+
pendingApprovals: [{ toolCallId: "tc_1", toolName: "deploy" } as any],
|
|
114
|
+
},
|
|
115
|
+
};
|
|
112
116
|
|
|
117
|
+
const surfaced = await updateWorkflowTaskApprovalStatus("wfx_1", "task_a", "aex_child");
|
|
118
|
+
|
|
119
|
+
expect(surfaced).toBe(true);
|
|
113
120
|
expect(capturedUpdates).toHaveLength(1);
|
|
114
121
|
const { status, options } = capturedUpdates[0];
|
|
115
122
|
expect(options.updatePendingApprovals).toBe(true);
|
|
116
123
|
expect(options.pendingUpdateChildAgentExecutionId).toBe("aex_child");
|
|
117
124
|
expect(status.pendingApprovals[0].childAgentExecutionId).toBe("aex_child");
|
|
125
|
+
expect(status.pendingApprovals[0].approval.toolCallId).toBe("tc_1");
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("updateWorkflowTaskApprovalStatus answers false and writes nothing when the child's gate already resolved", async () => {
|
|
129
|
+
// The child persists its gate before signaling, so an empty read means
|
|
130
|
+
// the gate resolved in the interim — surfacing it would show a stale
|
|
131
|
+
// approval card, and the orchestrator deliberately does not retry.
|
|
132
|
+
mockGetExecutionResult = { status: { pendingApprovals: [] } };
|
|
133
|
+
|
|
134
|
+
const surfaced = await updateWorkflowTaskApprovalStatus("wfx_1", "task_a", "aex_child");
|
|
135
|
+
|
|
136
|
+
expect(surfaced).toBe(false);
|
|
137
|
+
expect(capturedUpdates).toHaveLength(0);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("updateWorkflowTaskApprovalStatus is a no-op without a child id", async () => {
|
|
141
|
+
expect(await updateWorkflowTaskApprovalStatus("wfx_1", "task_a", "")).toBe(false);
|
|
142
|
+
expect(capturedUpdates).toHaveLength(0);
|
|
118
143
|
});
|
|
119
144
|
|
|
120
145
|
it("clearWorkflowApprovalStatus scopes the clear to the given child", async () => {
|
|
@@ -737,6 +737,7 @@ function makeConfig() {
|
|
|
737
737
|
runnerId: null,
|
|
738
738
|
checkpointerType: "memory" as const,
|
|
739
739
|
checkpointerProxyEndpoint: null,
|
|
740
|
+
artifactProxyEndpoint: null,
|
|
740
741
|
primaryModel: "gpt-4.1",
|
|
741
742
|
cursorStreamStallTimeoutMs: 180000,
|
|
742
743
|
agentResolveTimeoutMs: 120000,
|
|
@@ -913,6 +913,7 @@ function makeConfig() {
|
|
|
913
913
|
runnerId: null,
|
|
914
914
|
checkpointerType: "memory" as const,
|
|
915
915
|
checkpointerProxyEndpoint: null,
|
|
916
|
+
artifactProxyEndpoint: null,
|
|
916
917
|
primaryModel: "gpt-4.1",
|
|
917
918
|
cursorStreamStallTimeoutMs: 180000,
|
|
918
919
|
agentResolveTimeoutMs: 120000,
|
|
@@ -16,7 +16,6 @@ import { StigmerClient } from "../client/stigmer-client.js";
|
|
|
16
16
|
import { loadConfig } from "../config.js";
|
|
17
17
|
import { create } from "@bufbuild/protobuf";
|
|
18
18
|
import { WorkflowExecutionStatusSchema, WorkflowPendingApprovalSchema, WorkflowPendingFileReviewSchema } from "@stigmer/protos/ai/stigmer/agentic/workflowexecution/v1/api_pb";
|
|
19
|
-
import type { ChildApprovalNotification } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/approval_pb";
|
|
20
19
|
import { ToolCallStatus, FileChangeSetStatus } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
21
20
|
|
|
22
21
|
function buildClient(): StigmerClient {
|
|
@@ -27,23 +26,40 @@ function buildClient(): StigmerClient {
|
|
|
27
26
|
});
|
|
28
27
|
}
|
|
29
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Derives the child's approval gate onto the parent (DD-012: identity-only
|
|
31
|
+
* signal, derive-from-child). The signal carries only the child execution id;
|
|
32
|
+
* this activity reads the child's persisted `status.pending_approvals` — the
|
|
33
|
+
* single source of truth the child's server wrote BEFORE signaling — and
|
|
34
|
+
* mirrors it onto the parent as reference entries.
|
|
35
|
+
*
|
|
36
|
+
* Returns true when a gate was surfaced, false when the child currently has
|
|
37
|
+
* no pending approvals. The child persists its gate before the signal is
|
|
38
|
+
* sent (both editions), so an empty read means the gate already resolved
|
|
39
|
+
* (e.g. approved on the agent surface in the interim) — the caller must NOT
|
|
40
|
+
* retry: surfacing a resolved gate would show users a stale approval card.
|
|
41
|
+
*/
|
|
30
42
|
export async function updateWorkflowTaskApprovalStatus(
|
|
31
43
|
executionId: string,
|
|
32
44
|
_taskName: string,
|
|
33
|
-
|
|
34
|
-
): Promise<
|
|
35
|
-
if (!executionId) return;
|
|
45
|
+
childExecutionId: string,
|
|
46
|
+
): Promise<boolean> {
|
|
47
|
+
if (!executionId || !childExecutionId) return false;
|
|
36
48
|
|
|
37
|
-
const childExecId = notification.executionId;
|
|
38
49
|
const client = buildClient();
|
|
39
|
-
const
|
|
50
|
+
const child = await client.getExecution(childExecutionId);
|
|
51
|
+
const pendingApprovals = (child?.status?.pendingApprovals ?? []).map(
|
|
40
52
|
(approval) =>
|
|
41
53
|
create(WorkflowPendingApprovalSchema, {
|
|
42
54
|
approval,
|
|
43
|
-
childAgentExecutionId:
|
|
55
|
+
childAgentExecutionId: childExecutionId,
|
|
44
56
|
}),
|
|
45
57
|
);
|
|
46
58
|
|
|
59
|
+
if (pendingApprovals.length === 0) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
|
|
47
63
|
const status = create(WorkflowExecutionStatusSchema, {
|
|
48
64
|
pendingApprovals,
|
|
49
65
|
});
|
|
@@ -52,8 +68,9 @@ export async function updateWorkflowTaskApprovalStatus(
|
|
|
52
68
|
// approvals and preserves every parallel sibling's entries.
|
|
53
69
|
await client.updateWorkflowExecutionStatus(executionId, status, {
|
|
54
70
|
updatePendingApprovals: true,
|
|
55
|
-
pendingUpdateChildAgentExecutionId:
|
|
71
|
+
pendingUpdateChildAgentExecutionId: childExecutionId,
|
|
56
72
|
});
|
|
73
|
+
return true;
|
|
57
74
|
}
|
|
58
75
|
|
|
59
76
|
export async function clearWorkflowApprovalStatus(
|
|
@@ -251,6 +251,85 @@ describe("buildPrompt", () => {
|
|
|
251
251
|
expect(prompt).not.toContain("<declared_preferences>");
|
|
252
252
|
});
|
|
253
253
|
|
|
254
|
+
it("carries the recalled memories on the first execution, framed as user-confirmed background", () => {
|
|
255
|
+
const prompt = buildPrompt(
|
|
256
|
+
input({
|
|
257
|
+
resolution: resolution("local", "created_first_execution"),
|
|
258
|
+
recalledMemories: {
|
|
259
|
+
facts: ["Deploys to us-east-1.", "Prefers OpenTofu."],
|
|
260
|
+
},
|
|
261
|
+
}),
|
|
262
|
+
);
|
|
263
|
+
expect(prompt).toContain("<recalled_memories>");
|
|
264
|
+
expect(prompt).toContain("- Deploys to us-east-1.");
|
|
265
|
+
expect(prompt).toContain("- Prefers OpenTofu.");
|
|
266
|
+
// Memories are CONTEXT like the bridge; the approval protocol keeps
|
|
267
|
+
// its pinned last-before-task slot.
|
|
268
|
+
expect(prompt.indexOf("<recalled_memories>"))
|
|
269
|
+
.toBeLessThan(prompt.indexOf("<tool_approval_protocol>"));
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
it("orders remembered facts after declared preferences, before the embedder's session context (DD-006 D4)", () => {
|
|
273
|
+
const prompt = buildPrompt(
|
|
274
|
+
input({
|
|
275
|
+
resolution: resolution("local", "created_first_execution"),
|
|
276
|
+
declaredPreferences: { orgContext: "We deploy to us-east-1." },
|
|
277
|
+
recalledMemories: { facts: ["Prefers OpenTofu."] },
|
|
278
|
+
sessionContext: "Role: platform admin",
|
|
279
|
+
}),
|
|
280
|
+
);
|
|
281
|
+
const preferences = prompt.indexOf("<declared_preferences>");
|
|
282
|
+
const memories = prompt.indexOf("<recalled_memories>");
|
|
283
|
+
const context = prompt.indexOf("<session_context>");
|
|
284
|
+
expect(preferences).toBeGreaterThan(-1);
|
|
285
|
+
expect(memories).toBeGreaterThan(preferences);
|
|
286
|
+
expect(context).toBeGreaterThan(memories);
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
it("never re-sends the memories to a successfully resumed agent — frozen per session by design (DD-002 D3, inherited by DD-006 D4)", () => {
|
|
290
|
+
const prompt = buildPrompt(
|
|
291
|
+
input({
|
|
292
|
+
resolution: resolution("local", "resumed_successfully"),
|
|
293
|
+
recalledMemories: { facts: ["Prefers OpenTofu."] },
|
|
294
|
+
}),
|
|
295
|
+
);
|
|
296
|
+
expect(prompt).toBe(USER_MESSAGE);
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
it("omits the memories section when the execution carries none", () => {
|
|
300
|
+
const prompt = buildPrompt(
|
|
301
|
+
input({ resolution: resolution("local", "created_first_execution") }),
|
|
302
|
+
);
|
|
303
|
+
expect(prompt).not.toContain("<recalled_memories>");
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
it("carries the recalled memories through the HITL-recovery shape — the standing-context drop hazard (the buildFromPlan lesson)", () => {
|
|
307
|
+
// A fresh agent replacing a lost one mid-HITL gets the full recovery
|
|
308
|
+
// shape. Standing context is hand-copied into that shape's options at
|
|
309
|
+
// the buildPrompt routing — a missed copy would silently lose the
|
|
310
|
+
// memories for the session's whole life (frozen per session).
|
|
311
|
+
const approvalDecisions = new Map<string, ApprovalAction>([
|
|
312
|
+
["tool-call-1", ApprovalAction.APPROVE],
|
|
313
|
+
]);
|
|
314
|
+
const prompt = buildPrompt(
|
|
315
|
+
input({
|
|
316
|
+
resolution: resolution("local", "created_after_resume_failure"),
|
|
317
|
+
approvalDecisions,
|
|
318
|
+
recalledMemories: { facts: ["Prefers OpenTofu."] },
|
|
319
|
+
pendingApprovals: [
|
|
320
|
+
create(PendingApprovalSchema, {
|
|
321
|
+
toolCallId: "tool-call-1",
|
|
322
|
+
toolName: "Write",
|
|
323
|
+
message: "Write file: gated.txt",
|
|
324
|
+
}),
|
|
325
|
+
],
|
|
326
|
+
}),
|
|
327
|
+
);
|
|
328
|
+
expect(prompt).toContain("<recalled_memories>");
|
|
329
|
+
expect(prompt).toContain("- Prefers OpenTofu.");
|
|
330
|
+
expect(prompt).toContain("APPROVED");
|
|
331
|
+
});
|
|
332
|
+
|
|
254
333
|
it("uses the reinvocation prompt for a HITL reinvocation (human-meaningful, no opaque ids)", () => {
|
|
255
334
|
const approvalDecisions = new Map<string, ApprovalAction>([
|
|
256
335
|
["tool-call-1", ApprovalAction.APPROVE],
|
|
@@ -57,6 +57,7 @@ import {
|
|
|
57
57
|
} from "../../shared/caller-identity.js";
|
|
58
58
|
import { readSessionContext } from "../../shared/session-context.js";
|
|
59
59
|
import { readDeclaredPreferences } from "../../shared/declared-preferences.js";
|
|
60
|
+
import { readRecalledMemories } from "../../shared/recalled-memories.js";
|
|
60
61
|
import { withholdSecretContentFromMessages } from "../../shared/tool-row.js";
|
|
61
62
|
import { StallTimeoutError, formatStallFailure } from "../../shared/stall-watchdog.js";
|
|
62
63
|
import { resolveUsableArtifactStorage, loadArtifactStorageConfig, type ArtifactStorage } from "../../shared/artifact-storage.js";
|
|
@@ -83,6 +84,7 @@ import {
|
|
|
83
84
|
readChannelConversationId,
|
|
84
85
|
synthesizeConversationAttachment,
|
|
85
86
|
} from "../../shared/conversation-attachment.js";
|
|
87
|
+
import { synthesizeMemoryAttachment } from "../../shared/memory-attachment.js";
|
|
86
88
|
import { injectSynthesizedAttachment } from "../../shared/synthesized-attachment.js";
|
|
87
89
|
import { mergeApprovalPolicies } from "./approval-policy.js";
|
|
88
90
|
import { deriveActiveLeases, isUnattendedApprovalMode } from "../../shared/approval-policy.js";
|
|
@@ -716,6 +718,33 @@ async function executeCursorInner(
|
|
|
716
718
|
resolvedMcpServers, conversationAttachment, "conversation participation",
|
|
717
719
|
);
|
|
718
720
|
}
|
|
721
|
+
|
|
722
|
+
// Phase 4a5: Synthesize the memory capture attachment (DD-005 D1) —
|
|
723
|
+
// the fourth sibling. The recall snapshot's enabled bit IS the
|
|
724
|
+
// attachment decision (server-stamped at execution create; a free
|
|
725
|
+
// local read, like the conversation attachment's session label). The
|
|
726
|
+
// capture context is attribution the server verifies or trusts per
|
|
727
|
+
// edition (Stage 3 provenance decision); the subject is never
|
|
728
|
+
// threaded — it derives from the credential.
|
|
729
|
+
const memoryAttachment = synthesizeMemoryAttachment(
|
|
730
|
+
execution.spec?.recalledMemories,
|
|
731
|
+
{
|
|
732
|
+
org: session.metadata?.org ?? "",
|
|
733
|
+
agentId: blueprint.agent.metadata?.id ?? "",
|
|
734
|
+
sessionId,
|
|
735
|
+
agentExecutionId: executionId,
|
|
736
|
+
},
|
|
737
|
+
{
|
|
738
|
+
bridgeEndpoint: config.mcpBridgeEndpoint,
|
|
739
|
+
credential: attachmentCredential,
|
|
740
|
+
backendEndpoint: config.stigmerBackendEndpoint,
|
|
741
|
+
},
|
|
742
|
+
);
|
|
743
|
+
if (memoryAttachment) {
|
|
744
|
+
resolvedMcpServers = injectSynthesizedAttachment(
|
|
745
|
+
resolvedMcpServers, memoryAttachment, "memory capture",
|
|
746
|
+
);
|
|
747
|
+
}
|
|
719
748
|
// The one projection point: every mutation above is now visible in the
|
|
720
749
|
// Cursor SDK config by construction (no per-mutation rebuild to forget).
|
|
721
750
|
const mcpConfig = toCursorMcpConfig(resolvedMcpServers);
|
|
@@ -1179,6 +1208,7 @@ async function executeCursorInner(
|
|
|
1179
1208
|
senderIdentity: readSenderIdentity(blueprint.sessionSpec.metadata),
|
|
1180
1209
|
sessionContext: readSessionContext(blueprint.sessionSpec.metadata),
|
|
1181
1210
|
declaredPreferences: readDeclaredPreferences(spec.declaredPreferences),
|
|
1211
|
+
recalledMemories: readRecalledMemories(spec.recalledMemories),
|
|
1182
1212
|
conversationCatchup: readConversationCatchup(spec.conversationCatchup),
|
|
1183
1213
|
// The turn's recorded transcript, seeded from the persisted execution
|
|
1184
1214
|
// on a reinvocation (Phase 3). Consumed only by the HITL-recovery
|
|
@@ -1886,6 +1916,7 @@ async function executeCursorInner(
|
|
|
1886
1916
|
senderIdentity: readSenderIdentity(blueprint.sessionSpec.metadata),
|
|
1887
1917
|
sessionContext: readSessionContext(blueprint.sessionSpec.metadata),
|
|
1888
1918
|
declaredPreferences: readDeclaredPreferences(spec.declaredPreferences),
|
|
1919
|
+
recalledMemories: readRecalledMemories(spec.recalledMemories),
|
|
1889
1920
|
conversationCatchup: readConversationCatchup(spec.conversationCatchup),
|
|
1890
1921
|
// Composed fresh (not reused from Phase 10): the failed primary
|
|
1891
1922
|
// stream may have appended partial work onto status.messages,
|
|
@@ -2486,6 +2517,16 @@ export interface BuildPromptInput {
|
|
|
2486
2517
|
* store with identical content.
|
|
2487
2518
|
*/
|
|
2488
2519
|
declaredPreferences?: import("../../shared/declared-preferences.js").DeclaredPreferencesContent;
|
|
2520
|
+
/**
|
|
2521
|
+
* The subject's confirmed memories from the execution spec's
|
|
2522
|
+
* `recalled_memories` (stigmer/stigmer#293 Phase 2, DD-006). Like the
|
|
2523
|
+
* preferences, only the enhanced-prompt path consumes it — deliberately
|
|
2524
|
+
* frozen per Cursor session (DD-002 D3, inherited by DD-006 D4): the
|
|
2525
|
+
* first turn delivers it into the agent's own conversation store, and
|
|
2526
|
+
* repeating it on resumed turns would bloat the store with identical
|
|
2527
|
+
* content.
|
|
2528
|
+
*/
|
|
2529
|
+
recalledMemories?: import("../../shared/recalled-memories.js").RecalledMemoriesContent;
|
|
2489
2530
|
/**
|
|
2490
2531
|
* Conversation catchup from the execution spec's `conversation_catchup`
|
|
2491
2532
|
* (cloud DD-006): what happened on the channel conversation that the
|
|
@@ -2625,6 +2666,7 @@ export function buildPrompt(input: BuildPromptInput): string {
|
|
|
2625
2666
|
senderIdentity: input.senderIdentity,
|
|
2626
2667
|
sessionContext: input.sessionContext,
|
|
2627
2668
|
declaredPreferences: input.declaredPreferences,
|
|
2669
|
+
recalledMemories: input.recalledMemories,
|
|
2628
2670
|
conversationCatchup,
|
|
2629
2671
|
},
|
|
2630
2672
|
{
|
|
@@ -2692,6 +2734,7 @@ export function buildPrompt(input: BuildPromptInput): string {
|
|
|
2692
2734
|
senderIdentity: input.senderIdentity,
|
|
2693
2735
|
sessionContext: input.sessionContext,
|
|
2694
2736
|
declaredPreferences: input.declaredPreferences,
|
|
2737
|
+
recalledMemories: input.recalledMemories,
|
|
2695
2738
|
conversationCatchup,
|
|
2696
2739
|
});
|
|
2697
2740
|
}
|
|
@@ -35,6 +35,10 @@ import {
|
|
|
35
35
|
formatDeclaredPreferencesText,
|
|
36
36
|
type DeclaredPreferencesContent,
|
|
37
37
|
} from "../../shared/declared-preferences.js";
|
|
38
|
+
import {
|
|
39
|
+
formatRecalledMemoriesText,
|
|
40
|
+
type RecalledMemoriesContent,
|
|
41
|
+
} from "../../shared/recalled-memories.js";
|
|
38
42
|
import {
|
|
39
43
|
visionDisclosureLines,
|
|
40
44
|
type NotViewableEntry,
|
|
@@ -160,6 +164,16 @@ export interface EnhancedPromptOptions {
|
|
|
160
164
|
* it every resumed turn would bloat the store with identical content.
|
|
161
165
|
*/
|
|
162
166
|
declaredPreferences?: DeclaredPreferencesContent;
|
|
167
|
+
/**
|
|
168
|
+
* The subject's confirmed memories (stigmer/stigmer#293 Phase 2, DD-006):
|
|
169
|
+
* consent-gated facts server-snapshotted onto the execution spec's
|
|
170
|
+
* `recalled_memories` at create. Like the preferences, it lands in the
|
|
171
|
+
* first message and persists in the cursor agent's own conversation
|
|
172
|
+
* store — deliberately frozen per Cursor session (DD-002 D3, inherited
|
|
173
|
+
* by DD-006 D4): repeating it every resumed turn would bloat the store
|
|
174
|
+
* with identical content.
|
|
175
|
+
*/
|
|
176
|
+
recalledMemories?: RecalledMemoriesContent;
|
|
163
177
|
/**
|
|
164
178
|
* Conversation catchup (cloud DD-006): what happened on the channel
|
|
165
179
|
* conversation that the agent has not seen, read from the execution
|
|
@@ -253,6 +267,14 @@ export function buildEnhancedPrompt(options: EnhancedPromptOptions): string {
|
|
|
253
267
|
sections.push(formatDeclaredPreferencesSection(options.declaredPreferences));
|
|
254
268
|
}
|
|
255
269
|
|
|
270
|
+
// Declared-by-humans precedes learned-and-confirmed (DD-006 D4): both
|
|
271
|
+
// are platform-authored standing background, but a preference is the
|
|
272
|
+
// user's exact words while a memory is an agent's confirmed inference —
|
|
273
|
+
// the exact statement reads first.
|
|
274
|
+
if (options.recalledMemories) {
|
|
275
|
+
sections.push(formatRecalledMemoriesSection(options.recalledMemories));
|
|
276
|
+
}
|
|
277
|
+
|
|
256
278
|
// Standing facts about the user (session context) come before the
|
|
257
279
|
// carried conversation (bridge): the bridge may refer back to them.
|
|
258
280
|
if (options.sessionContext) {
|
|
@@ -472,6 +494,12 @@ export function formatDeclaredPreferencesSection(
|
|
|
472
494
|
return `<declared_preferences>\n${formatDeclaredPreferencesText(preferences)}\n</declared_preferences>`;
|
|
473
495
|
}
|
|
474
496
|
|
|
497
|
+
export function formatRecalledMemoriesSection(
|
|
498
|
+
memories: RecalledMemoriesContent,
|
|
499
|
+
): string {
|
|
500
|
+
return `<recalled_memories>\n${formatRecalledMemoriesText(memories)}\n</recalled_memories>`;
|
|
501
|
+
}
|
|
502
|
+
|
|
475
503
|
export function formatSessionContextSection(context: string): string {
|
|
476
504
|
return `<session_context>\n${formatSessionContextText(context)}\n</session_context>`;
|
|
477
505
|
}
|
|
@@ -251,6 +251,7 @@ const httpConfig: Config = {
|
|
|
251
251
|
cloudModeEnabled: true,
|
|
252
252
|
checkpointerType: "http",
|
|
253
253
|
checkpointerProxyEndpoint: "http://localhost:7234",
|
|
254
|
+
artifactProxyEndpoint: null,
|
|
254
255
|
primaryModel: "claude-sonnet",
|
|
255
256
|
cursorStreamStallTimeoutMs: 180000,
|
|
256
257
|
agentResolveTimeoutMs: 120000,
|
|
@@ -296,6 +296,7 @@ const baseConfig: Config = {
|
|
|
296
296
|
cloudModeEnabled: true,
|
|
297
297
|
checkpointerType: "http",
|
|
298
298
|
checkpointerProxyEndpoint: "http://localhost:7234",
|
|
299
|
+
artifactProxyEndpoint: null,
|
|
299
300
|
primaryModel: "claude-sonnet",
|
|
300
301
|
cursorStreamStallTimeoutMs: 180000,
|
|
301
302
|
agentResolveTimeoutMs: 120000,
|
|
@@ -250,6 +250,7 @@ const baseConfig: Config = {
|
|
|
250
250
|
cloudModeEnabled: true,
|
|
251
251
|
checkpointerType: "http",
|
|
252
252
|
checkpointerProxyEndpoint: "http://localhost:7234",
|
|
253
|
+
artifactProxyEndpoint: null,
|
|
253
254
|
primaryModel: "claude-sonnet",
|
|
254
255
|
cursorStreamStallTimeoutMs: 180000,
|
|
255
256
|
agentResolveTimeoutMs: 120000,
|
|
@@ -47,6 +47,7 @@ describe("ExecuteDeepAgent activity", () => {
|
|
|
47
47
|
cloudModeEnabled: false,
|
|
48
48
|
checkpointerType: "memory",
|
|
49
49
|
checkpointerProxyEndpoint: null,
|
|
50
|
+
artifactProxyEndpoint: null,
|
|
50
51
|
primaryModel: "gpt-4.1",
|
|
51
52
|
cursorStreamStallTimeoutMs: 180000,
|
|
52
53
|
agentResolveTimeoutMs: 120000,
|
|
@@ -14,6 +14,7 @@ const nothing = {
|
|
|
14
14
|
mcpServerUsageCount: 0,
|
|
15
15
|
channelMessagingCount: 0,
|
|
16
16
|
conversationChannelId: undefined,
|
|
17
|
+
memoryCaptureEnabled: false,
|
|
17
18
|
};
|
|
18
19
|
|
|
19
20
|
describe("shouldConnectMcp", () => {
|
|
@@ -34,4 +35,10 @@ describe("shouldConnectMcp", () => {
|
|
|
34
35
|
// channel — the escalation tool is the ONLY source.
|
|
35
36
|
expect(shouldConnectMcp({ ...nothing, conversationChannelId: "agch_1" })).toBe(true);
|
|
36
37
|
});
|
|
38
|
+
|
|
39
|
+
it("enters on memory capture alone (the memory attachment)", () => {
|
|
40
|
+
// A tool-less agent whose user has memory on: the remember tool is
|
|
41
|
+
// the ONLY source, and skipping the block would silently drop it.
|
|
42
|
+
expect(shouldConnectMcp({ ...nothing, memoryCaptureEnabled: true })).toBe(true);
|
|
43
|
+
});
|
|
37
44
|
});
|