@stigmer/runner 3.5.3 → 3.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.build-fingerprint +1 -1
- package/dist/activities/call-agent.js +85 -10
- package/dist/activities/call-agent.js.map +1 -1
- package/dist/activities/discover-mcp-server.js +9 -1
- package/dist/activities/discover-mcp-server.js.map +1 -1
- package/dist/activities/execute-cursor/index.d.ts +5 -0
- package/dist/activities/execute-cursor/index.js +88 -14
- package/dist/activities/execute-cursor/index.js.map +1 -1
- package/dist/activities/execute-cursor/model-pricing.d.ts +9 -0
- package/dist/activities/execute-cursor/model-pricing.js +19 -0
- package/dist/activities/execute-cursor/model-pricing.js.map +1 -1
- package/dist/activities/execute-cursor/prompt-builder.d.ts +7 -0
- package/dist/activities/execute-cursor/prompt-builder.js +9 -0
- package/dist/activities/execute-cursor/prompt-builder.js.map +1 -1
- package/dist/activities/execute-cursor/service-tier.d.ts +68 -0
- package/dist/activities/execute-cursor/service-tier.js +187 -0
- package/dist/activities/execute-cursor/service-tier.js.map +1 -0
- package/dist/activities/execute-cursor/session-lifecycle.d.ts +16 -1
- package/dist/activities/execute-cursor/session-lifecycle.js +12 -4
- package/dist/activities/execute-cursor/session-lifecycle.js.map +1 -1
- package/dist/activities/execute-cursor/usage-accumulator.d.ts +21 -1
- package/dist/activities/execute-cursor/usage-accumulator.js +23 -3
- package/dist/activities/execute-cursor/usage-accumulator.js.map +1 -1
- package/dist/activities/execute-deep-agent/prompt-builder.d.ts +6 -0
- package/dist/activities/execute-deep-agent/prompt-builder.js +3 -0
- package/dist/activities/execute-deep-agent/prompt-builder.js.map +1 -1
- package/dist/activities/execute-deep-agent/setup.js +45 -9
- package/dist/activities/execute-deep-agent/setup.js.map +1 -1
- package/dist/client/stigmer-client.d.ts +32 -1
- package/dist/client/stigmer-client.js +42 -2
- package/dist/client/stigmer-client.js.map +1 -1
- package/dist/main.js +18 -0
- package/dist/main.js.map +1 -1
- package/dist/runner.js +48 -0
- package/dist/runner.js.map +1 -1
- package/dist/sandbox-token-renewal.d.ts +65 -0
- package/dist/sandbox-token-renewal.js +169 -0
- package/dist/sandbox-token-renewal.js.map +1 -0
- package/dist/shared/artifact-storage.d.ts +17 -3
- package/dist/shared/artifact-storage.js +22 -4
- package/dist/shared/artifact-storage.js.map +1 -1
- package/dist/shared/caller-identity.d.ts +89 -0
- package/dist/shared/caller-identity.js +124 -0
- package/dist/shared/caller-identity.js.map +1 -0
- package/dist/shared/channel-attachment.d.ts +85 -0
- package/dist/shared/channel-attachment.js +203 -0
- package/dist/shared/channel-attachment.js.map +1 -0
- package/dist/shared/datastore-attachment.d.ts +2 -25
- package/dist/shared/datastore-attachment.js +1 -28
- package/dist/shared/datastore-attachment.js.map +1 -1
- package/dist/shared/synthesized-attachment.d.ts +51 -0
- package/dist/shared/synthesized-attachment.js +45 -0
- package/dist/shared/synthesized-attachment.js.map +1 -0
- package/dist/workflow-engine/loader.js +99 -2
- package/dist/workflow-engine/loader.js.map +1 -1
- package/dist/workflow-engine/tasks/call-agent.d.ts +0 -2
- package/dist/workflow-engine/tasks/call-agent.js +0 -2
- package/dist/workflow-engine/tasks/call-agent.js.map +1 -1
- package/dist/workflow-engine/types.d.ts +39 -7
- package/dist/workflow-engine/types.js.map +1 -1
- package/dist/workflows/call-agent-orchestrator.d.ts +3 -2
- package/dist/workflows/call-agent-orchestrator.js +8 -2
- package/dist/workflows/call-agent-orchestrator.js.map +1 -1
- package/package.json +2 -2
- package/src/__test-utils__/mock-client.ts +4 -0
- package/src/__tests__/sandbox-token-renewal.test.ts +174 -0
- package/src/activities/__tests__/call-agent-contracts.test.ts +4 -4
- package/src/activities/__tests__/call-agent.test.ts +219 -4
- package/src/activities/__tests__/discover-mcp-server.test.ts +49 -0
- package/src/activities/call-agent.ts +94 -10
- package/src/activities/discover-mcp-server.ts +13 -1
- package/src/activities/execute-cursor/__tests__/model-pricing.test.ts +20 -0
- package/src/activities/execute-cursor/__tests__/service-tier.test.ts +170 -0
- package/src/activities/execute-cursor/__tests__/usage-accumulator.test.ts +87 -1
- package/src/activities/execute-cursor/index.ts +121 -20
- package/src/activities/execute-cursor/model-pricing.ts +23 -0
- package/src/activities/execute-cursor/prompt-builder.ts +19 -0
- package/src/activities/execute-cursor/service-tier.ts +244 -0
- package/src/activities/execute-cursor/session-lifecycle.ts +33 -5
- package/src/activities/execute-cursor/usage-accumulator.ts +35 -3
- package/src/activities/execute-deep-agent/prompt-builder.ts +10 -0
- package/src/activities/execute-deep-agent/setup.ts +66 -10
- package/src/client/stigmer-client.ts +57 -4
- package/src/main.ts +20 -0
- package/src/runner.ts +62 -0
- package/src/sandbox-token-renewal.ts +212 -0
- package/src/shared/__tests__/caller-identity.test.ts +159 -0
- package/src/shared/__tests__/channel-attachment.test.ts +276 -0
- package/src/shared/__tests__/datastore-attachment.test.ts +4 -4
- package/src/shared/artifact-storage.ts +32 -7
- package/src/shared/caller-identity.ts +161 -0
- package/src/shared/channel-attachment.ts +237 -0
- package/src/shared/datastore-attachment.ts +2 -54
- package/src/shared/synthesized-attachment.ts +77 -0
- package/src/workflow-engine/__tests__/golden-execution.test.ts +8 -8
- package/src/workflow-engine/__tests__/loader.test.ts +192 -7
- package/src/workflow-engine/__tests__/tasks/call-agent.test.ts +9 -9
- package/src/workflow-engine/loader.ts +113 -2
- package/src/workflow-engine/tasks/call-agent.ts +0 -2
- package/src/workflow-engine/types.ts +40 -7
- package/src/workflows/call-agent-orchestrator.ts +8 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"call-agent.js","sourceRoot":"","sources":["../../../src/workflow-engine/tasks/call-agent.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"call-agent.js","sourceRoot":"","sources":["../../../src/workflow-engine/tasks/call-agent.ts"],"names":[],"mappings":"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"}
|
|
@@ -525,21 +525,53 @@ export type CallAgentFn = (config: AgentCallConfig, runtimeEnv: Record<string, u
|
|
|
525
525
|
/**
|
|
526
526
|
* Agent call configuration — mirrors the proto `AgentCallTaskConfig`.
|
|
527
527
|
* Parsed from the YAML `with:` block of a `call: agent` task.
|
|
528
|
+
*
|
|
529
|
+
* The agent may be referenced as "slug" (workflow's org) or "org/slug"
|
|
530
|
+
* (explicit org); there is no separate org field.
|
|
528
531
|
*/
|
|
529
532
|
export interface AgentCallConfig {
|
|
530
533
|
readonly agent: string;
|
|
531
534
|
readonly message: string;
|
|
532
|
-
readonly org?: string;
|
|
533
535
|
readonly env?: Record<string, string>;
|
|
534
|
-
readonly
|
|
536
|
+
readonly run_config?: AgentCallRunConfig;
|
|
535
537
|
readonly output?: AgentCallOutputContract;
|
|
536
538
|
readonly harness?: string;
|
|
539
|
+
readonly workspace_entries?: readonly AgentCallWorkspaceEntry[];
|
|
537
540
|
}
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
541
|
+
/**
|
|
542
|
+
* Mirrors the shared `ai.stigmer.agentic.session.v1.WorkspaceEntry` in its
|
|
543
|
+
* git-only form — the workflow surface rejects local_path sources at write
|
|
544
|
+
* time (no client is connected to serve one when a task fires), so by the
|
|
545
|
+
* time YAML reaches the runner only git_repo entries exist.
|
|
546
|
+
*
|
|
547
|
+
* The task's `environment_refs` sibling never appears in execution YAML:
|
|
548
|
+
* the server resolves it from the Workflow row at execution create.
|
|
549
|
+
*/
|
|
550
|
+
export interface AgentCallWorkspaceEntry {
|
|
551
|
+
readonly name?: string;
|
|
552
|
+
readonly source: {
|
|
553
|
+
readonly git_repo: {
|
|
554
|
+
readonly url: string;
|
|
555
|
+
readonly branch?: string;
|
|
556
|
+
};
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* Mirrors the shared `ai.stigmer.agentic.agentexecution.v1.RunConfig`
|
|
561
|
+
* (issue #358) — the same run-bound vocabulary schedules embed. Every
|
|
562
|
+
* field maps onto its `ExecutionConfig` namesake and is enforced by the
|
|
563
|
+
* runner's generic cost/tool-round guards; nothing here is decorative.
|
|
564
|
+
*/
|
|
565
|
+
export interface AgentCallRunConfig {
|
|
566
|
+
readonly model_name?: string;
|
|
567
|
+
readonly max_cost_usd?: number;
|
|
568
|
+
readonly max_tool_rounds?: number;
|
|
569
|
+
/**
|
|
570
|
+
* Canonical ServiceTier enum name ("SERVICE_TIER_STANDARD" /
|
|
571
|
+
* "SERVICE_TIER_FAST"); the loader maps the YAML shorthands
|
|
572
|
+
* ("standard"/"fast") to these, mirroring harness.
|
|
573
|
+
*/
|
|
574
|
+
readonly service_tier?: string;
|
|
543
575
|
}
|
|
544
576
|
export interface AgentCallOutputContract {
|
|
545
577
|
readonly schema: Record<string, unknown>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/workflow-engine/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AA6LH,MAAM,CAAC,MAAM,aAAa,GAAG,UAAU,CAAC;AACxC,MAAM,CAAC,MAAM,QAAQ,GAAG,KAAK,CAAC;AAC9B,MAAM,CAAC,MAAM,SAAS,GAAG,MAAM,CAAC;AAEhC,MAAM,UAAU,aAAa,CAAC,SAAwB;IACpD,OAAO,SAAS,KAAK,QAAQ,IAAI,SAAS,KAAK,SAAS,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,SAAwB;IACvD,OAAO,CACL,SAAS,KAAK,aAAa;QAC3B,SAAS,KAAK,QAAQ;QACtB,SAAS,KAAK,SAAS,CACxB,CAAC;AACJ,CAAC;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/workflow-engine/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AA6LH,MAAM,CAAC,MAAM,aAAa,GAAG,UAAU,CAAC;AACxC,MAAM,CAAC,MAAM,QAAQ,GAAG,KAAK,CAAC;AAC9B,MAAM,CAAC,MAAM,SAAS,GAAG,MAAM,CAAC;AAEhC,MAAM,UAAU,aAAa,CAAC,SAAwB;IACpD,OAAO,SAAS,KAAK,QAAQ,IAAI,SAAS,KAAK,SAAS,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,SAAwB;IACvD,OAAO,CACL,SAAS,KAAK,aAAa;QAC3B,SAAS,KAAK,QAAQ;QACtB,SAAS,KAAK,SAAS,CACxB,CAAC;AACJ,CAAC;AAytBD,wEAAwE;AACxE,cAAc;AACd,wEAAwE;AAExE;;;;;;;;;;GAUG;AACH,MAAM,OAAO,cAAe,SAAQ,KAAK;IAC9B,gBAAgB,CAAS;IAElC,YAAY,OAAe,EAAE,gBAAwB;QACnD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;QAC7B,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;IAC3C,CAAC;CACF"}
|
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
* 4. Updating workflow approval status via local activities
|
|
9
9
|
* 5. Returning the agent result when the activity completes
|
|
10
10
|
*
|
|
11
|
-
* The
|
|
12
|
-
*
|
|
11
|
+
* The workflow engine's CallAgentTaskBuilder (workflow-engine/tasks/
|
|
12
|
+
* call-agent.ts) calls `ctx.callAgent()`, which is wired to
|
|
13
|
+
* `orchestrateAgentCall()` in execute-serverless-workflow.ts.
|
|
13
14
|
*
|
|
14
15
|
* SANDBOX RULES: Only @temporalio/workflow imports, type-only imports,
|
|
15
16
|
* and pure logic. No Node.js built-ins.
|
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
* 4. Updating workflow approval status via local activities
|
|
9
9
|
* 5. Returning the agent result when the activity completes
|
|
10
10
|
*
|
|
11
|
-
* The
|
|
12
|
-
*
|
|
11
|
+
* The workflow engine's CallAgentTaskBuilder (workflow-engine/tasks/
|
|
12
|
+
* call-agent.ts) calls `ctx.callAgent()`, which is wired to
|
|
13
|
+
* `orchestrateAgentCall()` in execute-serverless-workflow.ts.
|
|
13
14
|
*
|
|
14
15
|
* SANDBOX RULES: Only @temporalio/workflow imports, type-only imports,
|
|
15
16
|
* and pure logic. No Node.js built-ins.
|
|
@@ -22,6 +23,11 @@ import { AgentCallError } from "../workflow-engine/types.js";
|
|
|
22
23
|
export const childApprovalRequired = defineSignal("child_approval_required");
|
|
23
24
|
/** Sent by the platform immediately after the child AgentExecution starts. */
|
|
24
25
|
export const childExecutionStarted = defineSignal("child_execution_started");
|
|
26
|
+
// The 1h ceiling is a deliberate platform constant, not a user knob: the
|
|
27
|
+
// old AgentCallTaskConfig declared a per-task `timeout` that nothing ever
|
|
28
|
+
// read, and #358 deleted it rather than declaring what isn't honored. The
|
|
29
|
+
// real per-run bound is run_config.max_cost_usd, enforced inside the
|
|
30
|
+
// agent execution itself.
|
|
25
31
|
const agentProxy = proxyActivities({
|
|
26
32
|
startToCloseTimeout: "1h",
|
|
27
33
|
retry: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"call-agent-orchestrator.js","sourceRoot":"","sources":["../../src/workflows/call-agent-orchestrator.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"call-agent-orchestrator.js","sourceRoot":"","sources":["../../src/workflows/call-agent-orchestrator.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stigmer/runner",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.7.0",
|
|
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",
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
"@opentelemetry/sdk-metrics": "^2.0.0",
|
|
86
86
|
"@opentelemetry/sdk-trace-base": "^2.0.0",
|
|
87
87
|
"@opentelemetry/sdk-trace-node": "^2.0.0",
|
|
88
|
-
"@stigmer/protos": "3.
|
|
88
|
+
"@stigmer/protos": "3.7.0",
|
|
89
89
|
"@temporalio/activity": "^1.11.0",
|
|
90
90
|
"@temporalio/client": "^1.11.0",
|
|
91
91
|
"@temporalio/common": "^1.11.0",
|
|
@@ -26,6 +26,10 @@ export function mockStigmerClient(overrides: MockMethods = {}): StigmerClient {
|
|
|
26
26
|
getRunnerScopedToken: vi.fn().mockResolvedValue(undefined),
|
|
27
27
|
getSession: vi.fn().mockResolvedValue({}),
|
|
28
28
|
updateSession: vi.fn().mockResolvedValue({}),
|
|
29
|
+
// No proactive channels by default — the everyday answer for most
|
|
30
|
+
// agents (DD-006 D2); tests opt in to a channel-bound agent.
|
|
31
|
+
listMessagingChannels: vi.fn().mockResolvedValue([]),
|
|
32
|
+
listChannelTemplates: vi.fn().mockResolvedValue([]),
|
|
29
33
|
getAgent: vi.fn().mockResolvedValue({}),
|
|
30
34
|
getAgentInstance: vi.fn().mockResolvedValue({}),
|
|
31
35
|
getMcpServer: vi.fn().mockResolvedValue({}),
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
isRenewableSandboxToken,
|
|
4
|
+
startSandboxTokenRenewal,
|
|
5
|
+
} from "../sandbox-token-renewal.js";
|
|
6
|
+
import type { SandboxTokenRenewal } from "../sandbox-token-renewal.js";
|
|
7
|
+
|
|
8
|
+
/** Build an unsigned JWT carrying exactly the claims under test. */
|
|
9
|
+
function fakeJwt(claims: Record<string, unknown>): string {
|
|
10
|
+
const b64 = (o: object) => Buffer.from(JSON.stringify(o)).toString("base64url");
|
|
11
|
+
return `${b64({ alg: "RS256", typ: "JWT" })}.${b64(claims)}.fake-signature`;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function nowSeconds(): number {
|
|
15
|
+
return Math.floor(Date.now() / 1000);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** A sandbox token issued now with the given lifetime. */
|
|
19
|
+
function sandboxToken(ttlSeconds: number, tokenType = "sandbox"): string {
|
|
20
|
+
const iat = nowSeconds();
|
|
21
|
+
return fakeJwt({ token_type: tokenType, iat, exp: iat + ttlSeconds });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
describe("isRenewableSandboxToken", () => {
|
|
25
|
+
it("accepts sandbox and workflow_sandbox tokens with an expiry", () => {
|
|
26
|
+
expect(isRenewableSandboxToken(sandboxToken(3600))).toBe(true);
|
|
27
|
+
expect(isRenewableSandboxToken(sandboxToken(3600, "workflow_sandbox"))).toBe(true);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("rejects every non-sandbox credential class", () => {
|
|
31
|
+
expect(isRenewableSandboxToken(sandboxToken(3600, "embedded_runner"))).toBe(false);
|
|
32
|
+
expect(isRenewableSandboxToken(sandboxToken(3600, "pool_sandbox"))).toBe(false);
|
|
33
|
+
expect(isRenewableSandboxToken(fakeJwt({ iat: 1, exp: 2 }))).toBe(false);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("rejects a renewable class without an expiry (renew-before-expiry is undefined)", () => {
|
|
37
|
+
expect(isRenewableSandboxToken(fakeJwt({ token_type: "sandbox" }))).toBe(false);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("rejects absent and undecodable tokens", () => {
|
|
41
|
+
expect(isRenewableSandboxToken(null)).toBe(false);
|
|
42
|
+
expect(isRenewableSandboxToken(undefined)).toBe(false);
|
|
43
|
+
expect(isRenewableSandboxToken("not-a-jwt")).toBe(false);
|
|
44
|
+
expect(isRenewableSandboxToken("a.%%%.c")).toBe(false);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
describe("startSandboxTokenRenewal", () => {
|
|
49
|
+
const silentLog = { log: vi.fn(), warn: vi.fn() };
|
|
50
|
+
let handle: SandboxTokenRenewal | undefined;
|
|
51
|
+
|
|
52
|
+
beforeEach(() => {
|
|
53
|
+
vi.useFakeTimers();
|
|
54
|
+
silentLog.log.mockClear();
|
|
55
|
+
silentLog.warn.mockClear();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
afterEach(() => {
|
|
59
|
+
handle?.stop();
|
|
60
|
+
handle = undefined;
|
|
61
|
+
vi.useRealTimers();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("renews at 80% of the issued lifetime and applies the fresh token", async () => {
|
|
65
|
+
const initial = sandboxToken(1000);
|
|
66
|
+
let current = initial;
|
|
67
|
+
// Mint lazily so the renewed token's iat reflects the (fake) clock at
|
|
68
|
+
// renewal time, exactly like the real server would stamp it.
|
|
69
|
+
const renew = vi.fn().mockImplementation(
|
|
70
|
+
async () => ({ token: sandboxToken(1000), expiresInSeconds: 1000 }),
|
|
71
|
+
);
|
|
72
|
+
const applyToken = vi.fn((t: string) => { current = t; });
|
|
73
|
+
|
|
74
|
+
handle = startSandboxTokenRenewal({
|
|
75
|
+
getToken: () => current, renew, applyToken, log: silentLog,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Just before the 80% point: nothing has fired.
|
|
79
|
+
await vi.advanceTimersByTimeAsync(790_000);
|
|
80
|
+
expect(renew).not.toHaveBeenCalled();
|
|
81
|
+
|
|
82
|
+
// Crossing 80% of the 1000s lifetime triggers the renewal.
|
|
83
|
+
await vi.advanceTimersByTimeAsync(20_000);
|
|
84
|
+
expect(renew).toHaveBeenCalledWith(initial);
|
|
85
|
+
expect(applyToken).toHaveBeenCalledTimes(1);
|
|
86
|
+
expect(current).not.toBe(initial);
|
|
87
|
+
|
|
88
|
+
// The next renewal is scheduled from the FRESH token's own lifetime:
|
|
89
|
+
// nothing re-fires within the first half of it.
|
|
90
|
+
renew.mockClear();
|
|
91
|
+
await vi.advanceTimersByTimeAsync(400_000);
|
|
92
|
+
expect(renew).not.toHaveBeenCalled();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("parks on a non-renewable credential and picks up a renewable swap (pool claim)", async () => {
|
|
96
|
+
let current = sandboxToken(86_400, "pool_sandbox");
|
|
97
|
+
const renew = vi.fn().mockResolvedValue({ token: sandboxToken(1000) });
|
|
98
|
+
const applyToken = vi.fn();
|
|
99
|
+
|
|
100
|
+
handle = startSandboxTokenRenewal({
|
|
101
|
+
getToken: () => current, renew, applyToken, log: silentLog,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// Parked: rechecks but never renews the pool credential.
|
|
105
|
+
await vi.advanceTimersByTimeAsync(300_000);
|
|
106
|
+
expect(renew).not.toHaveBeenCalled();
|
|
107
|
+
|
|
108
|
+
// The claim swaps in a session token (attach-session's updateToken).
|
|
109
|
+
current = sandboxToken(1000);
|
|
110
|
+
|
|
111
|
+
// Next recheck sees the renewable class and schedules from its lifetime.
|
|
112
|
+
await vi.advanceTimersByTimeAsync(60_000 + 800_000);
|
|
113
|
+
expect(renew).toHaveBeenCalled();
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("retries a failed renewal and succeeds on a later attempt", async () => {
|
|
117
|
+
const initial = sandboxToken(100);
|
|
118
|
+
const renewed = sandboxToken(1000);
|
|
119
|
+
let current = initial;
|
|
120
|
+
const renew = vi.fn()
|
|
121
|
+
.mockRejectedValueOnce(new Error("control plane unreachable"))
|
|
122
|
+
.mockResolvedValueOnce(undefined) // server minted nothing
|
|
123
|
+
.mockResolvedValue({ token: renewed });
|
|
124
|
+
const applyToken = vi.fn((t: string) => { current = t; });
|
|
125
|
+
|
|
126
|
+
handle = startSandboxTokenRenewal({
|
|
127
|
+
getToken: () => current, renew, applyToken, log: silentLog,
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// 80% of 100s is past MIN_DELAY, first attempt at ~80s, then two 60s retries.
|
|
131
|
+
await vi.advanceTimersByTimeAsync(80_000 + 60_000 + 60_000 + 5_000);
|
|
132
|
+
expect(renew).toHaveBeenCalledTimes(3);
|
|
133
|
+
expect(applyToken).toHaveBeenCalledWith(renewed);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it("attempts immediately when the pod boots with a token already past its renewal point", async () => {
|
|
137
|
+
// Issued 900s ago with a 1000s lifetime: 80% point long past.
|
|
138
|
+
const iat = nowSeconds() - 900;
|
|
139
|
+
const stale = fakeJwt({ token_type: "sandbox", iat, exp: iat + 1000 });
|
|
140
|
+
const renew = vi.fn().mockResolvedValue({ token: sandboxToken(1000) });
|
|
141
|
+
|
|
142
|
+
handle = startSandboxTokenRenewal({
|
|
143
|
+
getToken: () => stale, renew, applyToken: vi.fn(), log: silentLog,
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
await vi.advanceTimersByTimeAsync(0);
|
|
147
|
+
expect(renew).toHaveBeenCalledWith(stale);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("stop() cancels the loop", async () => {
|
|
151
|
+
const renew = vi.fn().mockResolvedValue({ token: sandboxToken(1000) });
|
|
152
|
+
|
|
153
|
+
handle = startSandboxTokenRenewal({
|
|
154
|
+
getToken: () => sandboxToken(100), renew, applyToken: vi.fn(), log: silentLog,
|
|
155
|
+
});
|
|
156
|
+
handle.stop();
|
|
157
|
+
|
|
158
|
+
await vi.advanceTimersByTimeAsync(600_000);
|
|
159
|
+
expect(renew).not.toHaveBeenCalled();
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it("parks (never spins) on a renewable-class token without an expiry", async () => {
|
|
163
|
+
const renew = vi.fn();
|
|
164
|
+
|
|
165
|
+
handle = startSandboxTokenRenewal({
|
|
166
|
+
getToken: () => fakeJwt({ token_type: "sandbox" }),
|
|
167
|
+
renew, applyToken: vi.fn(), log: silentLog,
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
await vi.advanceTimersByTimeAsync(300_000);
|
|
171
|
+
expect(renew).not.toHaveBeenCalled();
|
|
172
|
+
expect(silentLog.warn).toHaveBeenCalled();
|
|
173
|
+
});
|
|
174
|
+
});
|
|
@@ -400,7 +400,7 @@ describe("CallAgent server contract compliance", () => {
|
|
|
400
400
|
it("sets structuredOutputSchema when output.schema is present", async () => {
|
|
401
401
|
await exerciseCallAgent({
|
|
402
402
|
output: { schema: cohortSchema, on_invalid: "ON_INVALID_FAIL" },
|
|
403
|
-
|
|
403
|
+
run_config: { model_name: "claude-sonnet-4" },
|
|
404
404
|
});
|
|
405
405
|
const execConfig = capturedCreateExecution.spec.executionConfig;
|
|
406
406
|
expect(execConfig).toBeDefined();
|
|
@@ -414,7 +414,7 @@ describe("CallAgent server contract compliance", () => {
|
|
|
414
414
|
it("sets both modelName and structuredOutputSchema when both are present", async () => {
|
|
415
415
|
await exerciseCallAgent({
|
|
416
416
|
output: { schema: cohortSchema },
|
|
417
|
-
|
|
417
|
+
run_config: { model_name: "claude-sonnet-4" },
|
|
418
418
|
});
|
|
419
419
|
const execConfig = capturedCreateExecution.spec.executionConfig;
|
|
420
420
|
expect(execConfig.modelName).toBe("claude-sonnet-4");
|
|
@@ -433,7 +433,7 @@ describe("CallAgent server contract compliance", () => {
|
|
|
433
433
|
});
|
|
434
434
|
|
|
435
435
|
it("does not set structuredOutputSchema when output is absent", async () => {
|
|
436
|
-
await exerciseCallAgent({
|
|
436
|
+
await exerciseCallAgent({ run_config: { model_name: "claude-sonnet-4" } });
|
|
437
437
|
const execConfig = capturedCreateExecution.spec.executionConfig;
|
|
438
438
|
expect(execConfig).toBeDefined();
|
|
439
439
|
expect(execConfig.modelName).toBe("claude-sonnet-4");
|
|
@@ -459,7 +459,7 @@ describe("CallAgent server contract compliance", () => {
|
|
|
459
459
|
await exerciseCallAgent(
|
|
460
460
|
{
|
|
461
461
|
output: { schema: cohortSchema, on_invalid: "ON_INVALID_FAIL" },
|
|
462
|
-
|
|
462
|
+
run_config: { model_name: "claude-sonnet-4" },
|
|
463
463
|
harness: "HARNESS_CURSOR",
|
|
464
464
|
__taskName: "analyze_player_data",
|
|
465
465
|
} as any,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
2
|
import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
|
|
3
|
+
import { ServiceTier } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
3
4
|
|
|
4
5
|
let mockGetAgentByReference: ReturnType<typeof vi.fn>;
|
|
5
6
|
let mockCreateSession: ReturnType<typeof vi.fn>;
|
|
@@ -93,11 +94,11 @@ describe("callAgentAction", () => {
|
|
|
93
94
|
expect(ref.slug).toBe("my-agent");
|
|
94
95
|
});
|
|
95
96
|
|
|
96
|
-
it("
|
|
97
|
+
it("org/slug agent reference overrides the workflow org for lookup only", async () => {
|
|
97
98
|
await expect(
|
|
98
99
|
callAgentAction(
|
|
99
|
-
{ agent: "my-agent", message: "Hello"
|
|
100
|
-
{ __stigmer_org_id: "
|
|
100
|
+
{ agent: "explicit-org/my-agent", message: "Hello" },
|
|
101
|
+
{ __stigmer_org_id: "workflow-org" },
|
|
101
102
|
"wfl_parent789",
|
|
102
103
|
),
|
|
103
104
|
).rejects.toThrow("CompleteAsyncError");
|
|
@@ -106,6 +107,11 @@ describe("callAgentAction", () => {
|
|
|
106
107
|
expect(ref.org).toBe("explicit-org");
|
|
107
108
|
expect(ref.slug).toBe("my-agent");
|
|
108
109
|
expect(ref.kind).toBe(ApiResourceKind.agent);
|
|
110
|
+
|
|
111
|
+
// The execution itself is still created in the workflow's org — the
|
|
112
|
+
// cross-org reference changes agent lookup, never the billing org.
|
|
113
|
+
const execution = mockCreateAgentExecution.mock.calls[0][0];
|
|
114
|
+
expect(execution.metadata?.org).toBe("workflow-org");
|
|
109
115
|
});
|
|
110
116
|
});
|
|
111
117
|
|
|
@@ -120,7 +126,7 @@ describe("callAgentAction", () => {
|
|
|
120
126
|
).rejects.toThrow("call:agent requires an organization context");
|
|
121
127
|
});
|
|
122
128
|
|
|
123
|
-
it("
|
|
129
|
+
it("uses __stigmer_org_id from runtime env", async () => {
|
|
124
130
|
await expect(
|
|
125
131
|
callAgentAction(
|
|
126
132
|
{ agent: "my-agent", message: "Hello" },
|
|
@@ -260,4 +266,213 @@ describe("callAgentAction", () => {
|
|
|
260
266
|
expect(execution.spec.activityTaskQueue).toBe("");
|
|
261
267
|
});
|
|
262
268
|
});
|
|
269
|
+
|
|
270
|
+
describe("run_config → ExecutionConfig mapping (#358)", () => {
|
|
271
|
+
it("maps model_name, max_cost_usd, and max_tool_rounds onto ExecutionConfig", async () => {
|
|
272
|
+
await expect(
|
|
273
|
+
callAgentAction(
|
|
274
|
+
{
|
|
275
|
+
agent: "my-agent",
|
|
276
|
+
message: "Hello",
|
|
277
|
+
run_config: {
|
|
278
|
+
model_name: "claude-sonnet-4-6",
|
|
279
|
+
max_cost_usd: 0.75,
|
|
280
|
+
max_tool_rounds: 15,
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
{ __stigmer_org_id: "test-org" },
|
|
284
|
+
"wfl_parent",
|
|
285
|
+
),
|
|
286
|
+
).rejects.toThrow("CompleteAsyncError");
|
|
287
|
+
|
|
288
|
+
const execution = mockCreateAgentExecution.mock.calls[0][0];
|
|
289
|
+
expect(execution.spec.executionConfig).toBeDefined();
|
|
290
|
+
expect(execution.spec.executionConfig.modelName).toBe("claude-sonnet-4-6");
|
|
291
|
+
expect(execution.spec.executionConfig.maxCostUsd).toBe(0.75);
|
|
292
|
+
expect(execution.spec.executionConfig.maxToolRounds).toBe(15);
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
it("maps a canonical service_tier onto ExecutionConfig.serviceTier (#357)", async () => {
|
|
296
|
+
await expect(
|
|
297
|
+
callAgentAction(
|
|
298
|
+
{
|
|
299
|
+
agent: "my-agent",
|
|
300
|
+
message: "Hello",
|
|
301
|
+
run_config: { service_tier: "SERVICE_TIER_FAST" },
|
|
302
|
+
},
|
|
303
|
+
{ __stigmer_org_id: "test-org" },
|
|
304
|
+
"wfl_parent",
|
|
305
|
+
),
|
|
306
|
+
).rejects.toThrow("CompleteAsyncError");
|
|
307
|
+
|
|
308
|
+
const execution = mockCreateAgentExecution.mock.calls[0][0];
|
|
309
|
+
expect(execution.spec.executionConfig).toBeDefined();
|
|
310
|
+
expect(execution.spec.executionConfig.serviceTier).toBe(ServiceTier.FAST);
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
it("fails loudly on a service_tier value with no proto mapping", async () => {
|
|
314
|
+
// The loader canonicalizes tiers; an unmapped value reaching the
|
|
315
|
+
// activity means loader/activity drift. A pricing directive must
|
|
316
|
+
// never be silently dropped.
|
|
317
|
+
await expect(
|
|
318
|
+
callAgentAction(
|
|
319
|
+
{
|
|
320
|
+
agent: "my-agent",
|
|
321
|
+
message: "Hello",
|
|
322
|
+
run_config: { service_tier: "SERVICE_TIER_TURBO" },
|
|
323
|
+
},
|
|
324
|
+
{ __stigmer_org_id: "test-org" },
|
|
325
|
+
"wfl_parent",
|
|
326
|
+
),
|
|
327
|
+
).rejects.toThrow(
|
|
328
|
+
"call:agent run_config.service_tier 'SERVICE_TIER_TURBO' has no proto mapping",
|
|
329
|
+
);
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
it("omits ExecutionConfig entirely when run_config and output are absent", async () => {
|
|
333
|
+
await expect(
|
|
334
|
+
callAgentAction(
|
|
335
|
+
{ agent: "my-agent", message: "Hello" },
|
|
336
|
+
{ __stigmer_org_id: "test-org" },
|
|
337
|
+
"wfl_parent",
|
|
338
|
+
),
|
|
339
|
+
).rejects.toThrow("CompleteAsyncError");
|
|
340
|
+
|
|
341
|
+
const execution = mockCreateAgentExecution.mock.calls[0][0];
|
|
342
|
+
expect(execution.spec.executionConfig).toBeUndefined();
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
it("treats zero bounds as no override", async () => {
|
|
346
|
+
await expect(
|
|
347
|
+
callAgentAction(
|
|
348
|
+
{
|
|
349
|
+
agent: "my-agent",
|
|
350
|
+
message: "Hello",
|
|
351
|
+
run_config: { model_name: "claude-sonnet-4-6", max_cost_usd: 0, max_tool_rounds: 0 },
|
|
352
|
+
},
|
|
353
|
+
{ __stigmer_org_id: "test-org" },
|
|
354
|
+
"wfl_parent",
|
|
355
|
+
),
|
|
356
|
+
).rejects.toThrow("CompleteAsyncError");
|
|
357
|
+
|
|
358
|
+
const execution = mockCreateAgentExecution.mock.calls[0][0];
|
|
359
|
+
expect(execution.spec.executionConfig.modelName).toBe("claude-sonnet-4-6");
|
|
360
|
+
// Proto zero values: unset numerics read back as 0, but nothing was
|
|
361
|
+
// deliberately written — the guards must not have set them from a
|
|
362
|
+
// zero "no override" input.
|
|
363
|
+
expect(execution.spec.executionConfig.maxCostUsd).toBe(0);
|
|
364
|
+
expect(execution.spec.executionConfig.maxToolRounds).toBe(0);
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
describe("workspace entries and workflow provenance (#358 Phase 2)", () => {
|
|
369
|
+
it("maps git workspace entries onto the created session's spec", async () => {
|
|
370
|
+
await expect(
|
|
371
|
+
callAgentAction(
|
|
372
|
+
{
|
|
373
|
+
agent: "my-agent",
|
|
374
|
+
message: "Hello",
|
|
375
|
+
workspace_entries: [
|
|
376
|
+
{ name: "app", source: { git_repo: { url: "https://github.com/acme/app", branch: "main" } } },
|
|
377
|
+
{ source: { git_repo: { url: "https://github.com/acme/lib" } } },
|
|
378
|
+
],
|
|
379
|
+
},
|
|
380
|
+
{ __stigmer_org_id: "test-org" },
|
|
381
|
+
"wfl_parent",
|
|
382
|
+
),
|
|
383
|
+
).rejects.toThrow("CompleteAsyncError");
|
|
384
|
+
|
|
385
|
+
const session = mockCreateSession.mock.calls[0][0];
|
|
386
|
+
const entries = session.spec.workspaceEntries;
|
|
387
|
+
expect(entries).toHaveLength(2);
|
|
388
|
+
expect(entries[0].name).toBe("app");
|
|
389
|
+
expect(entries[0].source.source.case).toBe("gitRepo");
|
|
390
|
+
expect(entries[0].source.source.value.url).toBe("https://github.com/acme/app");
|
|
391
|
+
expect(entries[0].source.source.value.branch).toBe("main");
|
|
392
|
+
expect(entries[1].source.source.value.url).toBe("https://github.com/acme/lib");
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
it("creates sessions without workspace entries when none are configured", async () => {
|
|
396
|
+
await expect(
|
|
397
|
+
callAgentAction(
|
|
398
|
+
{ agent: "my-agent", message: "Hello" },
|
|
399
|
+
{ __stigmer_org_id: "test-org" },
|
|
400
|
+
"wfl_parent",
|
|
401
|
+
),
|
|
402
|
+
).rejects.toThrow("CompleteAsyncError");
|
|
403
|
+
|
|
404
|
+
const session = mockCreateSession.mock.calls[0][0];
|
|
405
|
+
expect(session.spec.workspaceEntries).toHaveLength(0);
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
it("stamps workflow provenance labels the server keys environment resolution on", async () => {
|
|
409
|
+
await expect(
|
|
410
|
+
callAgentAction(
|
|
411
|
+
{
|
|
412
|
+
agent: "my-agent",
|
|
413
|
+
message: "Hello",
|
|
414
|
+
__wfExecId: "wex_prov1",
|
|
415
|
+
__taskName: "triage",
|
|
416
|
+
} as any,
|
|
417
|
+
{ __stigmer_org_id: "test-org" },
|
|
418
|
+
"wfl_parent",
|
|
419
|
+
),
|
|
420
|
+
).rejects.toThrow("CompleteAsyncError");
|
|
421
|
+
|
|
422
|
+
const execution = mockCreateAgentExecution.mock.calls[0][0];
|
|
423
|
+
expect(execution.metadata.labels["stigmer.ai/workflow-execution-id"]).toBe("wex_prov1");
|
|
424
|
+
expect(execution.metadata.labels["stigmer.ai/workflow-task"]).toBe("triage");
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
it("stamps no provenance labels without workflow context", async () => {
|
|
428
|
+
await expect(
|
|
429
|
+
callAgentAction(
|
|
430
|
+
{ agent: "my-agent", message: "Hello" },
|
|
431
|
+
{ __stigmer_org_id: "test-org" },
|
|
432
|
+
"wfl_parent",
|
|
433
|
+
),
|
|
434
|
+
).rejects.toThrow("CompleteAsyncError");
|
|
435
|
+
|
|
436
|
+
const execution = mockCreateAgentExecution.mock.calls[0][0];
|
|
437
|
+
expect(Object.keys(execution.metadata.labels ?? {})).toHaveLength(0);
|
|
438
|
+
});
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
describe("env secret marking", () => {
|
|
442
|
+
it("preserves the agent-declared secret flag when a task env override supplies the value", async () => {
|
|
443
|
+
// The agent declares API_TOKEN as secret. A task-level env override
|
|
444
|
+
// provides the value — the secret marking must survive (#358: the
|
|
445
|
+
// override used to hardcode isSecret:false, a redaction downgrade).
|
|
446
|
+
mockGetAgentByReference.mockResolvedValue({
|
|
447
|
+
metadata: { id: "agt_test123" },
|
|
448
|
+
status: { defaultInstanceId: "ain_default456" },
|
|
449
|
+
spec: {
|
|
450
|
+
env: {
|
|
451
|
+
API_TOKEN: { isSecret: true },
|
|
452
|
+
REGION: { isSecret: false },
|
|
453
|
+
},
|
|
454
|
+
},
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
await expect(
|
|
458
|
+
callAgentAction(
|
|
459
|
+
{
|
|
460
|
+
agent: "my-agent",
|
|
461
|
+
message: "Hello",
|
|
462
|
+
env: { API_TOKEN: "resolved-secret-value", REGION: "us-east-1", EXTRA: "plain" },
|
|
463
|
+
},
|
|
464
|
+
{ __stigmer_org_id: "test-org" },
|
|
465
|
+
"wfl_parent",
|
|
466
|
+
),
|
|
467
|
+
).rejects.toThrow("CompleteAsyncError");
|
|
468
|
+
|
|
469
|
+
const execution = mockCreateAgentExecution.mock.calls[0][0];
|
|
470
|
+
const runtimeEnv = execution.spec.runtimeEnv;
|
|
471
|
+
expect(runtimeEnv.API_TOKEN.value).toBe("resolved-secret-value");
|
|
472
|
+
expect(runtimeEnv.API_TOKEN.isSecret).toBe(true);
|
|
473
|
+
expect(runtimeEnv.REGION.isSecret).toBe(false);
|
|
474
|
+
// Keys the agent never declared stay non-secret.
|
|
475
|
+
expect(runtimeEnv.EXTRA.isSecret).toBe(false);
|
|
476
|
+
});
|
|
477
|
+
});
|
|
263
478
|
});
|