@stigmer/runner 3.12.3 → 3.12.5
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-http.js +12 -0
- package/dist/activities/call-http.js.map +1 -1
- package/dist/activities/call-llm.d.ts +18 -0
- package/dist/activities/call-llm.js +56 -2
- package/dist/activities/call-llm.js.map +1 -1
- package/dist/activities/execute-cursor/agent-session-cache.d.ts +72 -0
- package/dist/activities/execute-cursor/agent-session-cache.js +186 -0
- package/dist/activities/execute-cursor/agent-session-cache.js.map +1 -0
- package/dist/activities/execute-cursor/cursor-mcp-config.d.ts +45 -0
- package/dist/activities/execute-cursor/cursor-mcp-config.js +76 -0
- package/dist/activities/execute-cursor/cursor-mcp-config.js.map +1 -0
- package/dist/activities/execute-cursor/index.d.ts +10 -1
- package/dist/activities/execute-cursor/index.js +108 -57
- package/dist/activities/execute-cursor/index.js.map +1 -1
- package/dist/activities/execute-cursor/prompt-builder.d.ts +13 -2
- 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-cursor/service-tier.d.ts +5 -15
- package/dist/activities/execute-cursor/service-tier.js +5 -21
- package/dist/activities/execute-cursor/service-tier.js.map +1 -1
- package/dist/activities/execute-cursor/session-lifecycle.d.ts +1 -1
- package/dist/activities/execute-cursor/skill-resolver.d.ts +2 -21
- package/dist/activities/execute-cursor/skill-resolver.js +5 -108
- package/dist/activities/execute-cursor/skill-resolver.js.map +1 -1
- package/dist/activities/execute-deep-agent/approval-file-change.d.ts +9 -0
- package/dist/activities/execute-deep-agent/approval-file-change.js +2 -1
- package/dist/activities/execute-deep-agent/approval-file-change.js.map +1 -1
- package/dist/activities/execute-deep-agent/cas-capture-backend.d.ts +18 -1
- package/dist/activities/execute-deep-agent/cas-capture-backend.js +20 -3
- package/dist/activities/execute-deep-agent/cas-capture-backend.js.map +1 -1
- package/dist/activities/execute-deep-agent/index.js +57 -5
- package/dist/activities/execute-deep-agent/index.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 +31 -16
- package/dist/activities/execute-deep-agent/setup.js.map +1 -1
- package/dist/activities/execute-deep-agent/shell-env.d.ts +8 -5
- package/dist/activities/execute-deep-agent/shell-env.js +10 -7
- package/dist/activities/execute-deep-agent/shell-env.js.map +1 -1
- package/dist/activities/execute-deep-agent/subagent-transformer.js +17 -11
- package/dist/activities/execute-deep-agent/subagent-transformer.js.map +1 -1
- package/dist/activities/execute-deep-agent/subagent-wiring.d.ts +3 -3
- package/dist/config.js +10 -5
- package/dist/config.js.map +1 -1
- package/dist/encryption/config.js +7 -2
- package/dist/encryption/config.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/main.js +12 -6
- package/dist/main.js.map +1 -1
- package/dist/middleware/path-normalization.d.ts +49 -49
- package/dist/middleware/path-normalization.js +73 -84
- package/dist/middleware/path-normalization.js.map +1 -1
- package/dist/middleware/types.d.ts +3 -3
- package/dist/payload-codecs.js +2 -1
- package/dist/payload-codecs.js.map +1 -1
- package/dist/runner-manager.d.ts +1 -1
- package/dist/runner-manager.js +42 -22
- package/dist/runner-manager.js.map +1 -1
- package/dist/runner.js +30 -6
- package/dist/runner.js.map +1 -1
- package/dist/shared/args-preview.d.ts +8 -0
- package/dist/shared/args-preview.js +14 -3
- package/dist/shared/args-preview.js.map +1 -1
- package/dist/shared/artifact-storage.d.ts +11 -1
- package/dist/shared/artifact-storage.js +10 -1
- package/dist/shared/artifact-storage.js.map +1 -1
- package/dist/shared/declared-preferences.d.ts +47 -0
- package/dist/shared/declared-preferences.js +64 -0
- package/dist/shared/declared-preferences.js.map +1 -0
- package/dist/shared/fingerprint-secret.d.ts +3 -2
- package/dist/shared/fingerprint-secret.js +5 -3
- package/dist/shared/fingerprint-secret.js.map +1 -1
- package/dist/shared/llm-backend.js +8 -1
- package/dist/shared/llm-backend.js.map +1 -1
- package/dist/shared/mcp-enabled-tools.d.ts +2 -3
- package/dist/shared/mcp-enabled-tools.js +2 -3
- package/dist/shared/mcp-enabled-tools.js.map +1 -1
- package/dist/shared/mcp-resolver.d.ts +20 -15
- package/dist/shared/mcp-resolver.js +11 -12
- package/dist/shared/mcp-resolver.js.map +1 -1
- package/dist/shared/model-client.d.ts +15 -0
- package/dist/shared/model-client.js +57 -13
- package/dist/shared/model-client.js.map +1 -1
- package/dist/shared/placeholder-resolver.d.ts +9 -2
- package/dist/shared/placeholder-resolver.js +9 -2
- package/dist/shared/placeholder-resolver.js.map +1 -1
- package/dist/shared/plan-mode-permissions.d.ts +26 -46
- package/dist/shared/plan-mode-permissions.js +27 -55
- package/dist/shared/plan-mode-permissions.js.map +1 -1
- package/dist/shared/registry-endpoint.d.ts +5 -0
- package/dist/shared/registry-endpoint.js +7 -1
- package/dist/shared/registry-endpoint.js.map +1 -1
- package/dist/shared/runner-credential-keys.d.ts +26 -1
- package/dist/shared/runner-credential-keys.js +34 -1
- package/dist/shared/runner-credential-keys.js.map +1 -1
- package/dist/shared/runner-credential-store.d.ts +77 -0
- package/dist/shared/runner-credential-store.js +111 -0
- package/dist/shared/runner-credential-store.js.map +1 -0
- package/dist/shared/service-tier.d.ts +55 -0
- package/dist/shared/service-tier.js +67 -0
- package/dist/shared/service-tier.js.map +1 -0
- package/dist/shared/skill-mount.d.ts +89 -0
- package/dist/shared/skill-mount.js +142 -0
- package/dist/shared/skill-mount.js.map +1 -0
- package/dist/shared/skill-writer.d.ts +28 -26
- package/dist/shared/skill-writer.js +79 -102
- package/dist/shared/skill-writer.js.map +1 -1
- package/dist/shared/worker-shutdown.d.ts +67 -0
- package/dist/shared/worker-shutdown.js +79 -0
- package/dist/shared/worker-shutdown.js.map +1 -0
- package/dist/shared/workspace/types.d.ts +3 -2
- package/dist/shared/zip-extract.d.ts +10 -3
- package/dist/shared/zip-extract.js +10 -3
- package/dist/shared/zip-extract.js.map +1 -1
- package/dist/workflow-engine/loader.js +38 -1
- package/dist/workflow-engine/loader.js.map +1 -1
- package/dist/workflow-engine/tasks/call-function.d.ts +14 -0
- package/dist/workflow-engine/tasks/call-function.js +49 -5
- package/dist/workflow-engine/tasks/call-function.js.map +1 -1
- package/dist/workflow-engine/tasks/human-input.js +23 -2
- package/dist/workflow-engine/tasks/human-input.js.map +1 -1
- package/dist/workflow-engine/types.d.ts +6 -0
- package/dist/workflow-engine/types.js.map +1 -1
- package/dist/workflows/engine-core.js +36 -8
- package/dist/workflows/engine-core.js.map +1 -1
- package/package.json +15 -11
- package/src/activities/__tests__/call-http.test.ts +36 -0
- package/src/activities/__tests__/call-llm.test.ts +77 -0
- package/src/activities/call-http.ts +17 -0
- package/src/activities/call-llm.ts +78 -2
- package/src/activities/execute-cursor/__tests__/agent-session-cache.test.ts +220 -0
- package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +50 -0
- package/src/activities/execute-cursor/__tests__/cursor-mcp-config.test.ts +111 -0
- package/src/activities/execute-cursor/__tests__/service-tier.test.ts +1 -1
- package/src/activities/execute-cursor/__tests__/skill-resolver.test.ts +3 -94
- package/src/activities/execute-cursor/agent-session-cache.ts +229 -0
- package/src/activities/execute-cursor/cursor-mcp-config.ts +107 -0
- package/src/activities/execute-cursor/index.ts +129 -55
- package/src/activities/execute-cursor/prompt-builder.ts +29 -2
- package/src/activities/execute-cursor/service-tier.ts +5 -29
- package/src/activities/execute-cursor/session-lifecycle.ts +1 -1
- package/src/activities/execute-cursor/skill-resolver.ts +10 -137
- package/src/activities/execute-deep-agent/__tests__/approval-file-change.test.ts +15 -0
- package/src/activities/execute-deep-agent/__tests__/cas-capture-backend.test.ts +75 -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__/plan-mode-path-normalization.test.ts +42 -29
- package/src/activities/execute-deep-agent/__tests__/prompt-builder.test.ts +52 -0
- package/src/activities/execute-deep-agent/__tests__/sequential-gate-resume.test.ts +1 -0
- package/src/activities/execute-deep-agent/__tests__/subagent-plan-mode-permissions.test.ts +11 -8
- package/src/activities/execute-deep-agent/approval-file-change.ts +11 -1
- package/src/activities/execute-deep-agent/cas-capture-backend.ts +20 -3
- package/src/activities/execute-deep-agent/index.ts +57 -5
- package/src/activities/execute-deep-agent/prompt-builder.ts +22 -0
- package/src/activities/execute-deep-agent/setup.ts +36 -19
- package/src/activities/execute-deep-agent/shell-env.ts +10 -7
- package/src/activities/execute-deep-agent/subagent-transformer.ts +19 -12
- package/src/activities/execute-deep-agent/subagent-wiring.ts +3 -3
- package/src/config.ts +10 -5
- package/src/encryption/config.ts +8 -2
- package/src/index.ts +1 -1
- package/src/main.ts +16 -6
- package/src/middleware/__tests__/path-normalization.test.ts +32 -32
- package/src/middleware/path-normalization.ts +78 -90
- package/src/middleware/types.ts +3 -3
- package/src/payload-codecs.ts +2 -1
- package/src/runner-manager.ts +55 -22
- package/src/runner.ts +39 -6
- package/src/shared/__tests__/artifact-storage.test.ts +28 -0
- package/src/shared/__tests__/bedrock-seam.test.ts +5 -5
- package/src/shared/__tests__/declared-preferences.test.ts +109 -0
- package/src/shared/__tests__/foundry-seam.test.ts +5 -5
- package/src/shared/__tests__/model-client.test.ts +99 -0
- package/src/shared/__tests__/plan-mode-permissions.test.ts +15 -44
- package/src/shared/__tests__/runner-credential-store.test.ts +155 -0
- package/src/shared/__tests__/skill-mount.test.ts +238 -0
- package/src/shared/__tests__/skill-writer.test.ts +151 -128
- package/src/shared/__tests__/vertex-adapter.test.ts +30 -3
- package/src/shared/__tests__/vertex-seam.test.ts +5 -5
- package/src/shared/__tests__/worker-shutdown.test.ts +101 -0
- package/src/shared/__tests__/zip-extract.test.ts +46 -11
- package/src/shared/args-preview.ts +17 -3
- package/src/shared/artifact-storage.ts +20 -1
- package/src/shared/declared-preferences.ts +84 -0
- package/src/shared/fingerprint-secret.ts +5 -3
- package/src/shared/llm-backend.ts +7 -1
- package/src/shared/mcp-enabled-tools.ts +2 -3
- package/src/shared/mcp-resolver.ts +20 -20
- package/src/shared/model-client.ts +76 -13
- package/src/shared/placeholder-resolver.ts +9 -2
- package/src/shared/plan-mode-permissions.ts +27 -58
- package/src/shared/registry-endpoint.ts +9 -1
- package/src/shared/runner-credential-keys.ts +36 -1
- package/src/shared/runner-credential-store.ts +115 -0
- package/src/shared/service-tier.ts +78 -0
- package/src/shared/skill-mount.ts +179 -0
- package/src/shared/skill-writer.ts +96 -130
- package/src/shared/worker-shutdown.ts +99 -0
- package/src/shared/workspace/types.ts +3 -2
- package/src/shared/zip-extract.ts +14 -7
- package/src/workflow-engine/__tests__/golden-execution.test.ts +20 -1
- package/src/workflow-engine/__tests__/loader.test.ts +51 -0
- package/src/workflow-engine/__tests__/tasks/call-function.test.ts +105 -0
- package/src/workflow-engine/__tests__/tasks/human-input.test.ts +117 -0
- package/src/workflow-engine/loader.ts +46 -1
- package/src/workflow-engine/tasks/call-function.ts +74 -13
- package/src/workflow-engine/tasks/human-input.ts +33 -5
- package/src/workflow-engine/types.ts +6 -0
- package/src/workflows/engine-core.ts +39 -8
- package/dist/activities/execute-cursor/connect-backfill.d.ts +0 -19
- package/dist/activities/execute-cursor/connect-backfill.js +0 -27
- package/dist/activities/execute-cursor/connect-backfill.js.map +0 -1
- package/dist/activities/execute-cursor/mcp-resolver.d.ts +0 -120
- package/dist/activities/execute-cursor/mcp-resolver.js +0 -194
- package/dist/activities/execute-cursor/mcp-resolver.js.map +0 -1
- package/dist/activities/execute-cursor/placeholder-resolver.d.ts +0 -34
- package/dist/activities/execute-cursor/placeholder-resolver.js +0 -82
- package/dist/activities/execute-cursor/placeholder-resolver.js.map +0 -1
- package/src/activities/execute-cursor/__tests__/mcp-resolver.test.ts +0 -125
- package/src/activities/execute-cursor/connect-backfill.ts +0 -52
- package/src/activities/execute-cursor/mcp-resolver.ts +0 -324
- package/src/activities/execute-cursor/placeholder-resolver.ts +0 -109
|
@@ -1528,6 +1528,57 @@ do:
|
|
|
1528
1528
|
}
|
|
1529
1529
|
});
|
|
1530
1530
|
|
|
1531
|
+
// The server converter persists on_timeout as the proto enum NAME
|
|
1532
|
+
// (HumanInputTimeoutPolicy.String()), so every applied workflow carries
|
|
1533
|
+
// that form in its validated YAML. stigmer/stigmer#779: the loader used
|
|
1534
|
+
// to cast it unvalidated, and the orchestrator's switch silently treated
|
|
1535
|
+
// the unrecognized string as fail.
|
|
1536
|
+
const humanInputYamlWithOnTimeout = (onTimeout: string) => `
|
|
1537
|
+
document:
|
|
1538
|
+
dsl: '1.0.0'
|
|
1539
|
+
name: test
|
|
1540
|
+
do:
|
|
1541
|
+
- timedApproval:
|
|
1542
|
+
call: human_input
|
|
1543
|
+
with:
|
|
1544
|
+
prompt: "Approve within time limit"
|
|
1545
|
+
timeout: 3600
|
|
1546
|
+
on_timeout: ${onTimeout}
|
|
1547
|
+
`;
|
|
1548
|
+
|
|
1549
|
+
it("call: human_input normalizes proto enum-name on_timeout values to the internal policy words", () => {
|
|
1550
|
+
const cases = [
|
|
1551
|
+
["HUMAN_INPUT_TIMEOUT_FAIL", "fail"],
|
|
1552
|
+
["HUMAN_INPUT_TIMEOUT_APPROVE", "approve"],
|
|
1553
|
+
["HUMAN_INPUT_TIMEOUT_DENY", "deny"],
|
|
1554
|
+
] as const;
|
|
1555
|
+
for (const [wireForm, internalForm] of cases) {
|
|
1556
|
+
const model = loadWorkflowFromYaml(humanInputYamlWithOnTimeout(wireForm));
|
|
1557
|
+
const task = model.do[0].task;
|
|
1558
|
+
expect(task.kind).toBe("human_input");
|
|
1559
|
+
if (task.kind === "human_input") {
|
|
1560
|
+
expect(task.humanInput.onTimeout).toBe(internalForm);
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
});
|
|
1564
|
+
|
|
1565
|
+
it("call: human_input rejects the not-implemented escalate policy at load time", () => {
|
|
1566
|
+
for (const form of ["HUMAN_INPUT_TIMEOUT_ESCALATE", "escalate"]) {
|
|
1567
|
+
expect(() => loadWorkflowFromYaml(humanInputYamlWithOnTimeout(form)))
|
|
1568
|
+
.toThrow(/timedApproval.*escalate.*not implemented/);
|
|
1569
|
+
}
|
|
1570
|
+
});
|
|
1571
|
+
|
|
1572
|
+
it("call: human_input rejects unknown on_timeout values instead of silently failing at timeout", () => {
|
|
1573
|
+
expect(() => loadWorkflowFromYaml(humanInputYamlWithOnTimeout("sometimes")))
|
|
1574
|
+
.toThrow(/timedApproval.*unknown on_timeout value 'sometimes'.*fail, approve, deny/);
|
|
1575
|
+
});
|
|
1576
|
+
|
|
1577
|
+
it("call: human_input rejects non-string on_timeout values", () => {
|
|
1578
|
+
expect(() => loadWorkflowFromYaml(humanInputYamlWithOnTimeout("42")))
|
|
1579
|
+
.toThrow(/timedApproval.*on_timeout/);
|
|
1580
|
+
});
|
|
1581
|
+
|
|
1531
1582
|
it("call: human_input with payload and ui_hint", () => {
|
|
1532
1583
|
const yaml = `
|
|
1533
1584
|
document:
|
|
@@ -208,6 +208,111 @@ describe("CallFunctionTaskBuilder", () => {
|
|
|
208
208
|
// The config resolver must never pre-evaluate them — the pre-fix
|
|
209
209
|
// behavior substituted the evaluated boolean back into the config and
|
|
210
210
|
// crashed the validate activity with `expr.includes is not a function`.
|
|
211
|
+
describe("llm on_invalid policy orchestration (#686)", () => {
|
|
212
|
+
const schemaTaskDef = (extra: Record<string, unknown>): CallFunctionTaskDef => ({
|
|
213
|
+
kind: "call:function",
|
|
214
|
+
call: "llm",
|
|
215
|
+
with: {
|
|
216
|
+
model: "gpt-4o-mini",
|
|
217
|
+
prompt: "Classify",
|
|
218
|
+
response_schema: { type: "object", properties: { answer: { type: "number" } } },
|
|
219
|
+
...extra,
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
const invalidResult = {
|
|
224
|
+
result: undefined, model: "gpt-4o-mini", provider: "openai",
|
|
225
|
+
input_tokens: 0, output_tokens: 0, parse_error: "answer: Required",
|
|
226
|
+
};
|
|
227
|
+
const validResult = {
|
|
228
|
+
result: { answer: 42 }, model: "gpt-4o-mini", provider: "openai",
|
|
229
|
+
input_tokens: 10, output_tokens: 5,
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
it("ON_INVALID_RETRY re-prompts with the validation errors and succeeds", async () => {
|
|
233
|
+
mockCallFunction
|
|
234
|
+
.mockResolvedValueOnce(invalidResult)
|
|
235
|
+
.mockResolvedValueOnce(validResult);
|
|
236
|
+
|
|
237
|
+
const builder = new CallFunctionTaskBuilder(
|
|
238
|
+
"classify", schemaTaskDef({ on_invalid: "ON_INVALID_RETRY", max_retries: 2 }),
|
|
239
|
+
);
|
|
240
|
+
const result = await builder.build()(null, createState(), makeCtx());
|
|
241
|
+
|
|
242
|
+
expect(result).toMatchObject({ structured: { answer: 42 } });
|
|
243
|
+
expect(mockCallFunction).toHaveBeenCalledTimes(2);
|
|
244
|
+
const retryConfig = mockCallFunction.mock.calls[1][1] as Record<string, unknown>;
|
|
245
|
+
expect(retryConfig.prompt).toContain("Classify");
|
|
246
|
+
expect(retryConfig.prompt).toContain("answer: Required");
|
|
247
|
+
expect(retryConfig.prompt).toContain("RETRY");
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it("ON_INVALID_RETRY exhausts max_retries then fails without a fallback_task", async () => {
|
|
251
|
+
mockCallFunction.mockResolvedValue(invalidResult);
|
|
252
|
+
|
|
253
|
+
const builder = new CallFunctionTaskBuilder(
|
|
254
|
+
"classify", schemaTaskDef({ on_invalid: "ON_INVALID_RETRY", max_retries: 2 }),
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
await expect(builder.build()(null, createState(), makeCtx()))
|
|
258
|
+
.rejects.toThrow(/validation failed after 3 attempt\(s\).*answer: Required/);
|
|
259
|
+
// first attempt + max_retries retries
|
|
260
|
+
expect(mockCallFunction).toHaveBeenCalledTimes(3);
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it("ON_INVALID_RETRY defaults max_retries to 1 (proto contract)", async () => {
|
|
264
|
+
mockCallFunction.mockResolvedValue(invalidResult);
|
|
265
|
+
|
|
266
|
+
const builder = new CallFunctionTaskBuilder(
|
|
267
|
+
"classify", schemaTaskDef({ on_invalid: "ON_INVALID_RETRY" }),
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
await expect(builder.build()(null, createState(), makeCtx())).rejects.toThrow();
|
|
271
|
+
expect(mockCallFunction).toHaveBeenCalledTimes(2);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
it("exhausted retries branch to fallback_task when set", async () => {
|
|
275
|
+
mockCallFunction.mockResolvedValue(invalidResult);
|
|
276
|
+
|
|
277
|
+
const builder = new CallFunctionTaskBuilder(
|
|
278
|
+
"classify",
|
|
279
|
+
schemaTaskDef({ on_invalid: "ON_INVALID_RETRY", max_retries: 1, fallback_task: "human_review" }),
|
|
280
|
+
);
|
|
281
|
+
const result = await builder.build()(null, createState(), makeCtx());
|
|
282
|
+
|
|
283
|
+
expect(result).toEqual({
|
|
284
|
+
__flow_directive__: "human_review",
|
|
285
|
+
validation_errors: ["answer: Required"],
|
|
286
|
+
});
|
|
287
|
+
expect(mockCallFunction).toHaveBeenCalledTimes(2);
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
it("ON_INVALID_FALLBACK branches immediately without retrying", async () => {
|
|
291
|
+
mockCallFunction.mockResolvedValue(invalidResult);
|
|
292
|
+
|
|
293
|
+
const builder = new CallFunctionTaskBuilder(
|
|
294
|
+
"classify",
|
|
295
|
+
schemaTaskDef({ on_invalid: "ON_INVALID_FALLBACK", fallback_task: "human_review" }),
|
|
296
|
+
);
|
|
297
|
+
const result = await builder.build()(null, createState(), makeCtx());
|
|
298
|
+
|
|
299
|
+
expect(result).toMatchObject({ __flow_directive__: "human_review" });
|
|
300
|
+
expect(mockCallFunction).toHaveBeenCalledTimes(1);
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
it("a parse_error without a soft policy passes through as normal output (activity owns the failure)", async () => {
|
|
304
|
+
// Default policy: the activity throws LLM_SCHEMA_VALIDATION itself and
|
|
305
|
+
// never returns parse_error — the engine must not add a second layer.
|
|
306
|
+
mockCallFunction.mockResolvedValue(validResult);
|
|
307
|
+
|
|
308
|
+
const builder = new CallFunctionTaskBuilder("classify", schemaTaskDef({}));
|
|
309
|
+
const result = await builder.build()(null, createState(), makeCtx());
|
|
310
|
+
|
|
311
|
+
expect(result).toMatchObject({ structured: { answer: 42 } });
|
|
312
|
+
expect(mockCallFunction).toHaveBeenCalledTimes(1);
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
|
|
211
316
|
describe("deferred expression fields", () => {
|
|
212
317
|
it("passes validate rules[].expression through unresolved while input and message interpolate", async () => {
|
|
213
318
|
mockCallFunction.mockResolvedValue({ valid: true, errors: [] });
|
|
@@ -246,6 +246,123 @@ describe("executeHumanInputTask", () => {
|
|
|
246
246
|
});
|
|
247
247
|
});
|
|
248
248
|
|
|
249
|
+
// HumanInputTaskConfig.outcomes contract (human_input.proto): with custom
|
|
250
|
+
// outcomes, timeout auto-approve resolves to the FIRST outcome and timeout
|
|
251
|
+
// auto-deny to the LAST — downstream `then` routing and outcome switches
|
|
252
|
+
// must see declared outcome names, never the internal approve/deny words a
|
|
253
|
+
// reviewer was never offered. stigmer/stigmer#779 made this path reachable
|
|
254
|
+
// for the first time.
|
|
255
|
+
describe("timeout outcome mapping with custom outcomes", () => {
|
|
256
|
+
const outcomes = [
|
|
257
|
+
{ name: "proceed", label: "Proceed", then: "deployStep" },
|
|
258
|
+
{ name: "needs_revision", label: "Needs revision", then: "gatherMore" },
|
|
259
|
+
{ name: "reject", label: "Reject" },
|
|
260
|
+
];
|
|
261
|
+
|
|
262
|
+
it("maps timeout auto-approve to the FIRST outcome and routes its then", async () => {
|
|
263
|
+
const awaitFn: AwaitHumanInputFn = async () => ({
|
|
264
|
+
outcome: "approve",
|
|
265
|
+
auto_resolved: true,
|
|
266
|
+
reason: "timeout",
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
const taskDef: HumanInputTaskDef = {
|
|
270
|
+
kind: "human_input",
|
|
271
|
+
humanInput: { prompt: "Review", timeout: 5, onTimeout: "approve", outcomes },
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
const state = createState();
|
|
275
|
+
const result = await executeHumanInputTask(taskDef, "gate", state, makeCtx(awaitFn));
|
|
276
|
+
|
|
277
|
+
expect(result).toEqual({
|
|
278
|
+
outcome: "proceed",
|
|
279
|
+
auto_resolved: true,
|
|
280
|
+
reason: "timeout",
|
|
281
|
+
__flow_directive__: "deployStep",
|
|
282
|
+
});
|
|
283
|
+
expect(state.data.gate).toEqual({
|
|
284
|
+
outcome: "proceed",
|
|
285
|
+
auto_resolved: true,
|
|
286
|
+
reason: "timeout",
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
it("maps timeout auto-deny to the LAST outcome", async () => {
|
|
291
|
+
const awaitFn: AwaitHumanInputFn = async () => ({
|
|
292
|
+
outcome: "deny",
|
|
293
|
+
auto_resolved: true,
|
|
294
|
+
reason: "timeout",
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
const taskDef: HumanInputTaskDef = {
|
|
298
|
+
kind: "human_input",
|
|
299
|
+
humanInput: { prompt: "Review", timeout: 5, onTimeout: "deny", outcomes },
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
const result = await executeHumanInputTask(taskDef, "gate", createState(), makeCtx(awaitFn));
|
|
303
|
+
|
|
304
|
+
// "reject" is the last outcome and declares no `then` — no directive.
|
|
305
|
+
expect(result).toEqual({ outcome: "reject", auto_resolved: true, reason: "timeout" });
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
it("reports the mapped outcome on the approval_resolved event", async () => {
|
|
309
|
+
const emitted: WorkflowEventDescriptor[][] = [];
|
|
310
|
+
const emitFn: EmitEventsFn = async (events) => { emitted.push(events); };
|
|
311
|
+
const awaitFn: AwaitHumanInputFn = async () => ({
|
|
312
|
+
outcome: "approve",
|
|
313
|
+
auto_resolved: true,
|
|
314
|
+
reason: "timeout",
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
const taskDef: HumanInputTaskDef = {
|
|
318
|
+
kind: "human_input",
|
|
319
|
+
humanInput: { prompt: "Review", timeout: 5, onTimeout: "approve", outcomes },
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
await executeHumanInputTask(taskDef, "gate", createState(), makeCtx(awaitFn, emitFn));
|
|
323
|
+
|
|
324
|
+
const resolved = emitted.flat().find((e) => e.type === "approval_resolved");
|
|
325
|
+
expect(resolved).toMatchObject({ outcome: "proceed", autoResolved: true });
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
it("leaves reviewer-selected outcomes untouched", async () => {
|
|
329
|
+
const awaitFn: AwaitHumanInputFn = async () => ({
|
|
330
|
+
outcome: "needs_revision",
|
|
331
|
+
reviewer: "alice",
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
const taskDef: HumanInputTaskDef = {
|
|
335
|
+
kind: "human_input",
|
|
336
|
+
humanInput: { prompt: "Review", timeout: 5, onTimeout: "approve", outcomes },
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
const result = await executeHumanInputTask(taskDef, "gate", createState(), makeCtx(awaitFn));
|
|
340
|
+
|
|
341
|
+
expect(result).toEqual({
|
|
342
|
+
outcome: "needs_revision",
|
|
343
|
+
reviewer: "alice",
|
|
344
|
+
__flow_directive__: "gatherMore",
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
it("keeps plain approve/deny for binary gates without custom outcomes", async () => {
|
|
349
|
+
const awaitFn: AwaitHumanInputFn = async () => ({
|
|
350
|
+
outcome: "approve",
|
|
351
|
+
auto_resolved: true,
|
|
352
|
+
reason: "timeout",
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
const taskDef: HumanInputTaskDef = {
|
|
356
|
+
kind: "human_input",
|
|
357
|
+
humanInput: { prompt: "Review", timeout: 5, onTimeout: "approve" },
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
const result = await executeHumanInputTask(taskDef, "gate", createState(), makeCtx(awaitFn));
|
|
361
|
+
|
|
362
|
+
expect(result).toEqual({ outcome: "approve", auto_resolved: true, reason: "timeout" });
|
|
363
|
+
});
|
|
364
|
+
});
|
|
365
|
+
|
|
249
366
|
describe("event emission", () => {
|
|
250
367
|
it("emits approval_requested before blocking with correct fields", async () => {
|
|
251
368
|
const emitted: WorkflowEventDescriptor[][] = [];
|
|
@@ -608,6 +608,51 @@ function parseServiceTier(raw: unknown): string | undefined {
|
|
|
608
608
|
return canonical;
|
|
609
609
|
}
|
|
610
610
|
|
|
611
|
+
/**
|
|
612
|
+
* Maps on_timeout values to the runner's internal policy words, mirroring
|
|
613
|
+
* SERVICE_TIER_SHORTHANDS. The persisted CNCF YAML carries the proto enum
|
|
614
|
+
* NAMES (the server converter emits `HumanInputTimeoutPolicy.String()`),
|
|
615
|
+
* while hand-written fixtures use the lowercase words — both are accepted.
|
|
616
|
+
* Unknown values are authoring errors: a timeout policy must never silently
|
|
617
|
+
* fall back to fail (stigmer/stigmer#779 — the unvalidated cast let every
|
|
618
|
+
* enum-name policy reach the orchestrator unrecognized, so gates configured
|
|
619
|
+
* to auto-approve/deny failed at their first real timeout instead).
|
|
620
|
+
*/
|
|
621
|
+
const ON_TIMEOUT_VOCABULARY: Record<string, "fail" | "approve" | "deny"> = {
|
|
622
|
+
fail: "fail",
|
|
623
|
+
approve: "approve",
|
|
624
|
+
deny: "deny",
|
|
625
|
+
HUMAN_INPUT_TIMEOUT_FAIL: "fail",
|
|
626
|
+
HUMAN_INPUT_TIMEOUT_APPROVE: "approve",
|
|
627
|
+
HUMAN_INPUT_TIMEOUT_DENY: "deny",
|
|
628
|
+
};
|
|
629
|
+
|
|
630
|
+
function parseOnTimeout(
|
|
631
|
+
taskName: string,
|
|
632
|
+
raw: unknown,
|
|
633
|
+
): "fail" | "approve" | "deny" | undefined {
|
|
634
|
+
if (raw === undefined || raw === null) return undefined;
|
|
635
|
+
if (typeof raw !== "string") {
|
|
636
|
+
throw new Error(`human_input task '${taskName}': 'on_timeout' must be a string`);
|
|
637
|
+
}
|
|
638
|
+
// The proto declares HUMAN_INPUT_TIMEOUT_ESCALATE but no runtime exists
|
|
639
|
+
// for it yet; refuse at load rather than misbehave at the gate's timeout.
|
|
640
|
+
if (raw === "HUMAN_INPUT_TIMEOUT_ESCALATE" || raw === "escalate") {
|
|
641
|
+
throw new Error(
|
|
642
|
+
`human_input task '${taskName}': on_timeout policy 'escalate' is not implemented — ` +
|
|
643
|
+
`use fail, approve, or deny (custom outcomes with 'then' cover reviewer-driven branching)`,
|
|
644
|
+
);
|
|
645
|
+
}
|
|
646
|
+
const policy = ON_TIMEOUT_VOCABULARY[raw];
|
|
647
|
+
if (!policy) {
|
|
648
|
+
throw new Error(
|
|
649
|
+
`human_input task '${taskName}': unknown on_timeout value '${raw}' ` +
|
|
650
|
+
`(expected: fail, approve, deny, or a HUMAN_INPUT_TIMEOUT_* enum name)`,
|
|
651
|
+
);
|
|
652
|
+
}
|
|
653
|
+
return policy;
|
|
654
|
+
}
|
|
655
|
+
|
|
611
656
|
function parseHumanInputConfig(taskName: string, raw: unknown): import("./types.js").HumanInputConfig {
|
|
612
657
|
if (!raw || typeof raw !== "object") {
|
|
613
658
|
throw new Error(`human_input task '${taskName}' requires a 'with' configuration block`);
|
|
@@ -630,7 +675,7 @@ function parseHumanInputConfig(taskName: string, raw: unknown): import("./types.
|
|
|
630
675
|
? obj.approvers.filter((a: unknown) => typeof a === "string") as string[]
|
|
631
676
|
: undefined,
|
|
632
677
|
timeout: typeof obj.timeout === "number" ? obj.timeout : undefined,
|
|
633
|
-
onTimeout: (obj.on_timeout
|
|
678
|
+
onTimeout: parseOnTimeout(taskName, obj.on_timeout),
|
|
634
679
|
// Any JSON shape is a valid payload (expression string, object, array),
|
|
635
680
|
// so only null/undefined mean "no payload" here.
|
|
636
681
|
payload: obj.payload ?? undefined,
|
|
@@ -162,26 +162,87 @@ export class CallFunctionTaskBuilder implements TaskBuilder {
|
|
|
162
162
|
const executionId =
|
|
163
163
|
(state.env.__stigmer_execution_id as string | undefined) || undefined;
|
|
164
164
|
|
|
165
|
-
const
|
|
166
|
-
callType,
|
|
167
|
-
resolved,
|
|
168
|
-
state.env,
|
|
169
|
-
{
|
|
170
|
-
workflowExecutionId: executionId,
|
|
171
|
-
},
|
|
172
|
-
);
|
|
165
|
+
const fnMeta = { workflowExecutionId: executionId };
|
|
173
166
|
|
|
174
167
|
if (callType === "llm") {
|
|
175
|
-
return
|
|
176
|
-
result as LlmActivityResult,
|
|
177
|
-
!!resolved.response_schema,
|
|
178
|
-
);
|
|
168
|
+
return this.executeLlmCall(resolved, state.env, fnMeta, ctx);
|
|
179
169
|
}
|
|
180
170
|
|
|
181
|
-
return
|
|
171
|
+
return ctx.callFunction(callType, resolved, state.env, fnMeta);
|
|
182
172
|
};
|
|
183
173
|
}
|
|
184
174
|
|
|
175
|
+
/**
|
|
176
|
+
* Executes a `call: llm` with schema-validation policy orchestration —
|
|
177
|
+
* the llm twin of call-agent's output-contract loop (#686).
|
|
178
|
+
*
|
|
179
|
+
* With ON_INVALID_RETRY / ON_INVALID_FALLBACK the activity reports a
|
|
180
|
+
* validation miss as a `parse_error` result instead of throwing; each
|
|
181
|
+
* retry is its own activity invocation (visible in Temporal history)
|
|
182
|
+
* re-prompting with the validation errors so the model can self-correct.
|
|
183
|
+
* Exhausted retries (or immediate FALLBACK) branch to `fallback_task`
|
|
184
|
+
* via the engine's flow directive; without one, the task fails — the
|
|
185
|
+
* proto contract. ON_INVALID_FAIL (default) keeps the activity's
|
|
186
|
+
* throwing path: one attempt, LLM_SCHEMA_VALIDATION on miss.
|
|
187
|
+
*/
|
|
188
|
+
private async executeLlmCall(
|
|
189
|
+
resolved: Record<string, unknown>,
|
|
190
|
+
env: Record<string, unknown>,
|
|
191
|
+
fnMeta: { workflowExecutionId?: string },
|
|
192
|
+
ctx: Parameters<TaskExecutorFn>[2],
|
|
193
|
+
): Promise<unknown> {
|
|
194
|
+
const hasSchema = !!resolved.response_schema;
|
|
195
|
+
const onInvalid = (resolved.on_invalid as string | undefined) ?? "ON_INVALID_FAIL";
|
|
196
|
+
const softHandling =
|
|
197
|
+
hasSchema && (onInvalid === "ON_INVALID_RETRY" || onInvalid === "ON_INVALID_FALLBACK");
|
|
198
|
+
|
|
199
|
+
// Proto: max_retries "Default: 1", meaningful only for ON_INVALID_RETRY.
|
|
200
|
+
const maxRetries =
|
|
201
|
+
onInvalid === "ON_INVALID_RETRY" ? (resolved.max_retries as number | undefined) ?? 1 : 0;
|
|
202
|
+
|
|
203
|
+
let attempts = 0;
|
|
204
|
+
let lastParseError = "";
|
|
205
|
+
|
|
206
|
+
do {
|
|
207
|
+
const attemptConfig =
|
|
208
|
+
attempts === 0
|
|
209
|
+
? resolved
|
|
210
|
+
: {
|
|
211
|
+
...resolved,
|
|
212
|
+
prompt:
|
|
213
|
+
`${resolved.prompt}\n\n[RETRY — Your previous response did not match ` +
|
|
214
|
+
`the required output schema. Validation errors: ${lastParseError}. ` +
|
|
215
|
+
`Please ensure your response strictly matches the JSON schema provided.]`,
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
const result = (await ctx.callFunction(
|
|
219
|
+
"llm",
|
|
220
|
+
attemptConfig,
|
|
221
|
+
env,
|
|
222
|
+
fnMeta,
|
|
223
|
+
)) as LlmActivityResult;
|
|
224
|
+
|
|
225
|
+
if (!softHandling || !result.parse_error) {
|
|
226
|
+
return normalizeLlmOutput(result, hasSchema);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
lastParseError = result.parse_error;
|
|
230
|
+
attempts++;
|
|
231
|
+
} while (onInvalid === "ON_INVALID_RETRY" && attempts <= maxRetries);
|
|
232
|
+
|
|
233
|
+
if (typeof resolved.fallback_task === "string" && resolved.fallback_task !== "") {
|
|
234
|
+
return {
|
|
235
|
+
__flow_directive__: resolved.fallback_task,
|
|
236
|
+
validation_errors: [lastParseError],
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
throw new Error(
|
|
241
|
+
`LLM output validation failed after ${attempts} attempt(s) ` +
|
|
242
|
+
`for task '${this.taskName}': ${lastParseError}`,
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
|
|
185
246
|
async shouldRun(): Promise<boolean> {
|
|
186
247
|
return true;
|
|
187
248
|
}
|
|
@@ -96,11 +96,14 @@ export async function executeHumanInputTask(
|
|
|
96
96
|
]);
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
const result: HumanInputResult =
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
99
|
+
const result: HumanInputResult = applyTimeoutOutcomeContract(
|
|
100
|
+
await ctx.awaitHumanInput({
|
|
101
|
+
signalName,
|
|
102
|
+
timeoutSeconds,
|
|
103
|
+
onTimeout,
|
|
104
|
+
}),
|
|
105
|
+
config.outcomes,
|
|
106
|
+
);
|
|
104
107
|
|
|
105
108
|
if (ctx.emitEvents) {
|
|
106
109
|
await ctx.emitEvents([{
|
|
@@ -132,6 +135,31 @@ function validateConfig(config: HumanInputConfig, taskName: string): void {
|
|
|
132
135
|
}
|
|
133
136
|
}
|
|
134
137
|
|
|
138
|
+
/**
|
|
139
|
+
* Applies the proto contract for timeout auto-resolution with custom
|
|
140
|
+
* outcomes (HumanInputTaskConfig.outcomes doc): auto-approve resolves to
|
|
141
|
+
* the FIRST declared outcome and auto-deny to the LAST, so `then` routing
|
|
142
|
+
* and downstream outcome switches see declared outcome names — never the
|
|
143
|
+
* orchestrator's internal approve/deny words, which a reviewer of a
|
|
144
|
+
* custom-outcome gate was never offered. Binary gates (no custom outcomes)
|
|
145
|
+
* keep the plain approve/deny result.
|
|
146
|
+
*/
|
|
147
|
+
function applyTimeoutOutcomeContract(
|
|
148
|
+
result: HumanInputResult,
|
|
149
|
+
outcomes: HumanInputConfig["outcomes"],
|
|
150
|
+
): HumanInputResult {
|
|
151
|
+
if (!result.auto_resolved || result.reason !== "timeout" || !outcomes?.length) {
|
|
152
|
+
return result;
|
|
153
|
+
}
|
|
154
|
+
if (result.outcome === "approve") {
|
|
155
|
+
return { ...result, outcome: outcomes[0].name };
|
|
156
|
+
}
|
|
157
|
+
if (result.outcome === "deny") {
|
|
158
|
+
return { ...result, outcome: outcomes[outcomes.length - 1].name };
|
|
159
|
+
}
|
|
160
|
+
return result;
|
|
161
|
+
}
|
|
162
|
+
|
|
135
163
|
interface ResolvedReviewPayload {
|
|
136
164
|
/** Resolved payload for inline delivery on the approval_requested event. */
|
|
137
165
|
readonly payload?: unknown;
|
|
@@ -336,6 +336,12 @@ export interface HttpCallConfig {
|
|
|
336
336
|
readonly query?: Record<string, string>;
|
|
337
337
|
readonly output?: string;
|
|
338
338
|
readonly redirect?: string;
|
|
339
|
+
/**
|
|
340
|
+
* Request timeout in seconds (proto: HttpCallTaskConfig.timeout_seconds,
|
|
341
|
+
* 1-300). Aborts the request and fails the task with HTTP_CALL_TIMEOUT;
|
|
342
|
+
* the engine also widens the activity's startToClose to fit it (#686).
|
|
343
|
+
*/
|
|
344
|
+
readonly timeout_seconds?: number;
|
|
339
345
|
}
|
|
340
346
|
|
|
341
347
|
export type EndpointDef = string | { readonly uri: string; readonly authentication?: Record<string, unknown> };
|
|
@@ -67,17 +67,44 @@ const evalProxy = proxyLocalActivities<EvalActivities>({
|
|
|
67
67
|
startToCloseTimeout: "10s",
|
|
68
68
|
});
|
|
69
69
|
|
|
70
|
+
const CALL_PROXY_RETRY = {
|
|
71
|
+
maximumAttempts: 5,
|
|
72
|
+
initialInterval: "1s",
|
|
73
|
+
backoffCoefficient: 2,
|
|
74
|
+
maximumInterval: "1m",
|
|
75
|
+
} as const;
|
|
76
|
+
|
|
70
77
|
const callProxy = proxyActivities<HttpActivities & GrpcActivities & FunctionActivities>({
|
|
71
78
|
startToCloseTimeout: "5m",
|
|
72
79
|
heartbeatTimeout: "30s",
|
|
73
|
-
retry:
|
|
74
|
-
maximumAttempts: 5,
|
|
75
|
-
initialInterval: "1s",
|
|
76
|
-
backoffCoefficient: 2,
|
|
77
|
-
maximumInterval: "1m",
|
|
78
|
-
},
|
|
80
|
+
retry: CALL_PROXY_RETRY,
|
|
79
81
|
});
|
|
80
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Task-config timeouts (llm_call.timeout ≤600s, http_call.timeout_seconds
|
|
85
|
+
* ≤300s) can exceed or crowd the default 5m startToClose, which would kill
|
|
86
|
+
* the activity before its own well-typed LLM_TIMEOUT / HTTP_CALL_TIMEOUT
|
|
87
|
+
* failure fires. When a task declares a budget, proxy its call with
|
|
88
|
+
* startToClose = budget + 30s so the in-activity bound always wins (#686).
|
|
89
|
+
*
|
|
90
|
+
* proxyActivities in workflow code is a deterministic proxy construction
|
|
91
|
+
* (no Temporal commands); the memo just avoids rebuilding per call.
|
|
92
|
+
*/
|
|
93
|
+
const timeoutAwareProxies = new Map<number, typeof callProxy>();
|
|
94
|
+
function callProxyFor(timeoutSeconds: number | undefined): typeof callProxy {
|
|
95
|
+
if (!timeoutSeconds || !Number.isFinite(timeoutSeconds)) return callProxy;
|
|
96
|
+
let proxy = timeoutAwareProxies.get(timeoutSeconds);
|
|
97
|
+
if (!proxy) {
|
|
98
|
+
proxy = proxyActivities<HttpActivities & GrpcActivities & FunctionActivities>({
|
|
99
|
+
startToCloseTimeout: `${timeoutSeconds + 30}s`,
|
|
100
|
+
heartbeatTimeout: "30s",
|
|
101
|
+
retry: CALL_PROXY_RETRY,
|
|
102
|
+
});
|
|
103
|
+
timeoutAwareProxies.set(timeoutSeconds, proxy);
|
|
104
|
+
}
|
|
105
|
+
return proxy;
|
|
106
|
+
}
|
|
107
|
+
|
|
81
108
|
const runProxy = proxyActivities<RunActivities>({
|
|
82
109
|
startToCloseTimeout: "5m",
|
|
83
110
|
heartbeatTimeout: "30s",
|
|
@@ -240,7 +267,7 @@ export async function runWorkflowEngine(
|
|
|
240
267
|
runWorkflow: (config: RunWorkflowExecutionConfig) => orchestrateRunWorkflow(config),
|
|
241
268
|
awaitHumanInput: (config: HumanInputExecutionConfig) => orchestrateHumanInput(config),
|
|
242
269
|
callHttp: (config: HttpCallConfig, runtimeEnv: Record<string, unknown>) =>
|
|
243
|
-
|
|
270
|
+
callProxyFor(config.timeout_seconds).CallHttp(config, runtimeEnv),
|
|
244
271
|
callGrpc: (config: GrpcCallConfig, runtimeEnv: Record<string, unknown>) =>
|
|
245
272
|
callProxy.CallGrpc(config, runtimeEnv),
|
|
246
273
|
callFunction: (
|
|
@@ -249,7 +276,11 @@ export async function runWorkflowEngine(
|
|
|
249
276
|
runtimeEnv: Record<string, unknown>,
|
|
250
277
|
fnMeta: CallFunctionMetadata,
|
|
251
278
|
) =>
|
|
252
|
-
|
|
279
|
+
callProxyFor(
|
|
280
|
+
call === "llm" && typeof config.timeout === "number"
|
|
281
|
+
? config.timeout
|
|
282
|
+
: undefined,
|
|
283
|
+
).CallFunction(
|
|
253
284
|
call,
|
|
254
285
|
config,
|
|
255
286
|
runtimeEnv,
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Connect backfill for MCP servers without discovered capabilities.
|
|
3
|
-
*
|
|
4
|
-
* Thin wrapper around the shared connect-backfill module that preserves
|
|
5
|
-
* the cursor-specific McpResolutionResult interface (which includes
|
|
6
|
-
* cursorConfig). The core backfill logic lives in shared/connect-backfill.ts.
|
|
7
|
-
*
|
|
8
|
-
* Non-fatal: if connect fails for any server, the original servers are
|
|
9
|
-
* kept and execution continues with empty policies (fail-closed).
|
|
10
|
-
*/
|
|
11
|
-
import type { McpResolutionResult } from "./mcp-resolver.js";
|
|
12
|
-
import type { StigmerClient } from "../../client/stigmer-client.js";
|
|
13
|
-
import type { McpTransportPosture } from "../../shared/mcp-transport-guard.js";
|
|
14
|
-
import type { McpServerUsage } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/spec_pb";
|
|
15
|
-
/**
|
|
16
|
-
* Run connect backfill and return an updated cursor-specific
|
|
17
|
-
* McpResolutionResult with rebuilt cursorConfig.
|
|
18
|
-
*/
|
|
19
|
-
export declare function backfillMcpServersIfNeeded(client: StigmerClient, currentResult: McpResolutionResult, usages: McpServerUsage[], envVars: Record<string, string>, org: string, transportPosture: McpTransportPosture, onHeartbeat?: () => void, secretKeys?: ReadonlySet<string>): Promise<McpResolutionResult>;
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Connect backfill for MCP servers without discovered capabilities.
|
|
3
|
-
*
|
|
4
|
-
* Thin wrapper around the shared connect-backfill module that preserves
|
|
5
|
-
* the cursor-specific McpResolutionResult interface (which includes
|
|
6
|
-
* cursorConfig). The core backfill logic lives in shared/connect-backfill.ts.
|
|
7
|
-
*
|
|
8
|
-
* Non-fatal: if connect fails for any server, the original servers are
|
|
9
|
-
* kept and execution continues with empty policies (fail-closed).
|
|
10
|
-
*/
|
|
11
|
-
import { toCursorMcpConfig } from "./mcp-resolver.js";
|
|
12
|
-
import { backfillMcpServersIfNeeded as sharedBackfill } from "../../shared/connect-backfill.js";
|
|
13
|
-
/**
|
|
14
|
-
* Run connect backfill and return an updated cursor-specific
|
|
15
|
-
* McpResolutionResult with rebuilt cursorConfig.
|
|
16
|
-
*/
|
|
17
|
-
export async function backfillMcpServersIfNeeded(client, currentResult, usages, envVars, org, transportPosture, onHeartbeat, secretKeys) {
|
|
18
|
-
const updatedServers = await sharedBackfill(client, currentResult.resolvedServers, usages, envVars, org, transportPosture, onHeartbeat, secretKeys);
|
|
19
|
-
if (updatedServers === currentResult.resolvedServers) {
|
|
20
|
-
return currentResult;
|
|
21
|
-
}
|
|
22
|
-
return {
|
|
23
|
-
cursorConfig: toCursorMcpConfig(updatedServers),
|
|
24
|
-
resolvedServers: updatedServers,
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
//# sourceMappingURL=connect-backfill.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"connect-backfill.js","sourceRoot":"","sources":["../../../src/activities/execute-cursor/connect-backfill.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAItD,OAAO,EAAE,0BAA0B,IAAI,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAEhG;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,MAAqB,EACrB,aAAkC,EAClC,MAAwB,EACxB,OAA+B,EAC/B,GAAW,EACX,gBAAqC,EACrC,WAAwB,EACxB,UAAgC;IAEhC,MAAM,cAAc,GAAG,MAAM,cAAc,CACzC,MAAM,EACN,aAAa,CAAC,eAAe,EAC7B,MAAM,EACN,OAAO,EACP,GAAG,EACH,gBAAgB,EAChB,WAAW,EACX,UAAU,CACX,CAAC;IAEF,IAAI,cAAc,KAAK,aAAa,CAAC,eAAe,EAAE,CAAC;QACrD,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,OAAO;QACL,YAAY,EAAE,iBAAiB,CAAC,cAAc,CAAC;QAC/C,eAAe,EAAE,cAAc;KAChC,CAAC;AACJ,CAAC"}
|