@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.
Files changed (101) hide show
  1. package/dist/.build-fingerprint +1 -1
  2. package/dist/activities/call-agent.js +85 -10
  3. package/dist/activities/call-agent.js.map +1 -1
  4. package/dist/activities/discover-mcp-server.js +9 -1
  5. package/dist/activities/discover-mcp-server.js.map +1 -1
  6. package/dist/activities/execute-cursor/index.d.ts +5 -0
  7. package/dist/activities/execute-cursor/index.js +88 -14
  8. package/dist/activities/execute-cursor/index.js.map +1 -1
  9. package/dist/activities/execute-cursor/model-pricing.d.ts +9 -0
  10. package/dist/activities/execute-cursor/model-pricing.js +19 -0
  11. package/dist/activities/execute-cursor/model-pricing.js.map +1 -1
  12. package/dist/activities/execute-cursor/prompt-builder.d.ts +7 -0
  13. package/dist/activities/execute-cursor/prompt-builder.js +9 -0
  14. package/dist/activities/execute-cursor/prompt-builder.js.map +1 -1
  15. package/dist/activities/execute-cursor/service-tier.d.ts +68 -0
  16. package/dist/activities/execute-cursor/service-tier.js +187 -0
  17. package/dist/activities/execute-cursor/service-tier.js.map +1 -0
  18. package/dist/activities/execute-cursor/session-lifecycle.d.ts +16 -1
  19. package/dist/activities/execute-cursor/session-lifecycle.js +12 -4
  20. package/dist/activities/execute-cursor/session-lifecycle.js.map +1 -1
  21. package/dist/activities/execute-cursor/usage-accumulator.d.ts +21 -1
  22. package/dist/activities/execute-cursor/usage-accumulator.js +23 -3
  23. package/dist/activities/execute-cursor/usage-accumulator.js.map +1 -1
  24. package/dist/activities/execute-deep-agent/prompt-builder.d.ts +6 -0
  25. package/dist/activities/execute-deep-agent/prompt-builder.js +3 -0
  26. package/dist/activities/execute-deep-agent/prompt-builder.js.map +1 -1
  27. package/dist/activities/execute-deep-agent/setup.js +45 -9
  28. package/dist/activities/execute-deep-agent/setup.js.map +1 -1
  29. package/dist/client/stigmer-client.d.ts +32 -1
  30. package/dist/client/stigmer-client.js +42 -2
  31. package/dist/client/stigmer-client.js.map +1 -1
  32. package/dist/main.js +18 -0
  33. package/dist/main.js.map +1 -1
  34. package/dist/runner.js +48 -0
  35. package/dist/runner.js.map +1 -1
  36. package/dist/sandbox-token-renewal.d.ts +65 -0
  37. package/dist/sandbox-token-renewal.js +169 -0
  38. package/dist/sandbox-token-renewal.js.map +1 -0
  39. package/dist/shared/artifact-storage.d.ts +17 -3
  40. package/dist/shared/artifact-storage.js +22 -4
  41. package/dist/shared/artifact-storage.js.map +1 -1
  42. package/dist/shared/caller-identity.d.ts +89 -0
  43. package/dist/shared/caller-identity.js +124 -0
  44. package/dist/shared/caller-identity.js.map +1 -0
  45. package/dist/shared/channel-attachment.d.ts +85 -0
  46. package/dist/shared/channel-attachment.js +203 -0
  47. package/dist/shared/channel-attachment.js.map +1 -0
  48. package/dist/shared/datastore-attachment.d.ts +2 -25
  49. package/dist/shared/datastore-attachment.js +1 -28
  50. package/dist/shared/datastore-attachment.js.map +1 -1
  51. package/dist/shared/synthesized-attachment.d.ts +51 -0
  52. package/dist/shared/synthesized-attachment.js +45 -0
  53. package/dist/shared/synthesized-attachment.js.map +1 -0
  54. package/dist/workflow-engine/loader.js +99 -2
  55. package/dist/workflow-engine/loader.js.map +1 -1
  56. package/dist/workflow-engine/tasks/call-agent.d.ts +0 -2
  57. package/dist/workflow-engine/tasks/call-agent.js +0 -2
  58. package/dist/workflow-engine/tasks/call-agent.js.map +1 -1
  59. package/dist/workflow-engine/types.d.ts +39 -7
  60. package/dist/workflow-engine/types.js.map +1 -1
  61. package/dist/workflows/call-agent-orchestrator.d.ts +3 -2
  62. package/dist/workflows/call-agent-orchestrator.js +8 -2
  63. package/dist/workflows/call-agent-orchestrator.js.map +1 -1
  64. package/package.json +2 -2
  65. package/src/__test-utils__/mock-client.ts +4 -0
  66. package/src/__tests__/sandbox-token-renewal.test.ts +174 -0
  67. package/src/activities/__tests__/call-agent-contracts.test.ts +4 -4
  68. package/src/activities/__tests__/call-agent.test.ts +219 -4
  69. package/src/activities/__tests__/discover-mcp-server.test.ts +49 -0
  70. package/src/activities/call-agent.ts +94 -10
  71. package/src/activities/discover-mcp-server.ts +13 -1
  72. package/src/activities/execute-cursor/__tests__/model-pricing.test.ts +20 -0
  73. package/src/activities/execute-cursor/__tests__/service-tier.test.ts +170 -0
  74. package/src/activities/execute-cursor/__tests__/usage-accumulator.test.ts +87 -1
  75. package/src/activities/execute-cursor/index.ts +121 -20
  76. package/src/activities/execute-cursor/model-pricing.ts +23 -0
  77. package/src/activities/execute-cursor/prompt-builder.ts +19 -0
  78. package/src/activities/execute-cursor/service-tier.ts +244 -0
  79. package/src/activities/execute-cursor/session-lifecycle.ts +33 -5
  80. package/src/activities/execute-cursor/usage-accumulator.ts +35 -3
  81. package/src/activities/execute-deep-agent/prompt-builder.ts +10 -0
  82. package/src/activities/execute-deep-agent/setup.ts +66 -10
  83. package/src/client/stigmer-client.ts +57 -4
  84. package/src/main.ts +20 -0
  85. package/src/runner.ts +62 -0
  86. package/src/sandbox-token-renewal.ts +212 -0
  87. package/src/shared/__tests__/caller-identity.test.ts +159 -0
  88. package/src/shared/__tests__/channel-attachment.test.ts +276 -0
  89. package/src/shared/__tests__/datastore-attachment.test.ts +4 -4
  90. package/src/shared/artifact-storage.ts +32 -7
  91. package/src/shared/caller-identity.ts +161 -0
  92. package/src/shared/channel-attachment.ts +237 -0
  93. package/src/shared/datastore-attachment.ts +2 -54
  94. package/src/shared/synthesized-attachment.ts +77 -0
  95. package/src/workflow-engine/__tests__/golden-execution.test.ts +8 -8
  96. package/src/workflow-engine/__tests__/loader.test.ts +192 -7
  97. package/src/workflow-engine/__tests__/tasks/call-agent.test.ts +9 -9
  98. package/src/workflow-engine/loader.ts +113 -2
  99. package/src/workflow-engine/tasks/call-agent.ts +0 -2
  100. package/src/workflow-engine/types.ts +40 -7
  101. package/src/workflows/call-agent-orchestrator.ts +8 -2
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Self-renewal of a cloud sandbox's control-plane credential (STIGMER_TOKEN).
3
+ *
4
+ * A sandbox token is minted with a fixed TTL, but the sandbox it serves has
5
+ * no fixed lifetime: an active conversation extends a session sandbox
6
+ * indefinitely, and a long workflow run can outlast any TTL chosen at
7
+ * provisioning. Before this module, the only refresh path was the control
8
+ * plane's Secret-rewrite + pod restart — which the 2026-08-05 incident
9
+ * showed both sacrifices the turn that trips it (the old pod picks up the
10
+ * work holding the dead env token) and wipes an ephemeral sandbox's
11
+ * workspace. Renewal decouples credential lifetime from sandbox lifetime:
12
+ * the runner re-mints in-process before expiry via the getRunnerScopedToken
13
+ * `renewal` arm, and the server bounds renewability by the live sandbox
14
+ * record (a reaped sandbox's credential dies with it).
15
+ *
16
+ * Relationship to {@link createRunnerTokenCoordinator}
17
+ * (runner-token-coordinator.ts): the coordinator owns the PROXY credential
18
+ * (x-stigmer-auth) and re-mints it using the control-plane token; this
19
+ * module keeps that control-plane token itself fresh, so the two form one
20
+ * chain with no expiring root. They stay separate modules because their
21
+ * hosts differ — every proxy-mode runner has a coordinator, but only
22
+ * in-cluster sandbox runners (static cloud sandboxes and pool members) hold
23
+ * a renewable credential; the desktop's control-plane token is the user's
24
+ * own Auth0 token, refreshed by the host app.
25
+ *
26
+ * The loop re-reads the CURRENT token every cycle rather than binding to
27
+ * the boot credential, because the credential's class can change under it:
28
+ * a pool member boots with a non-renewable pool_sandbox token and swaps to
29
+ * a renewable session token at claim time (attach-session.ts). A
30
+ * non-renewable token parks the loop on a slow recheck instead of stopping
31
+ * it, so the swap is picked up without any coupling to the claim path.
32
+ */
33
+ /**
34
+ * Renew once the token has lived this fraction of its issued lifetime
35
+ * (anchored on iat/exp, the coordinator's 0.8 convention). Anchoring on the
36
+ * ISSUED lifetime matters: a fraction of the *remaining* lifetime re-arms at
37
+ * 80% of an ever-shrinking remainder and never reaches the renewal point.
38
+ */
39
+ const RENEW_AT_LIFETIME_FRACTION = 0.8;
40
+ /**
41
+ * Fallback safety margin before expiry for a token without an iat claim:
42
+ * renew this early, leaving room for two retry cycles.
43
+ */
44
+ const FALLBACK_RENEW_MARGIN_MS = 10 * 60_000;
45
+ /** Retry delay after a failed renewal — short enough to recover well before expiry. */
46
+ const RETRY_DELAY_MS = 60_000;
47
+ /** Recheck cadence while the current token is not a renewable class (pre-claim pool member). */
48
+ const RECHECK_DELAY_MS = 60_000;
49
+ /** Floor for any scheduled delay so a malformed expiry cannot spin a hot loop. */
50
+ const MIN_DELAY_MS = 5_000;
51
+ /** The token_type claims the renewal arm accepts (mirrors the server's gate). */
52
+ const RENEWABLE_TOKEN_TYPES = new Set(["sandbox", "workflow_sandbox"]);
53
+ /**
54
+ * Whether a token's decoded claims mark it as renewable through the
55
+ * `renewal` arm. Exported so a static-mode host can decide not to start
56
+ * the loop at all for a credential whose class can never change.
57
+ */
58
+ export function isRenewableSandboxToken(token) {
59
+ const claims = decodeClaims(token);
60
+ return claims !== null
61
+ && RENEWABLE_TOKEN_TYPES.has(claims.tokenType ?? "")
62
+ && claims.expMs !== null;
63
+ }
64
+ /**
65
+ * Start the renewal loop. The first cycle runs immediately (it only reads
66
+ * the token and schedules; no network call unless the credential is already
67
+ * past its renewal point).
68
+ */
69
+ export function startSandboxTokenRenewal(options) {
70
+ const log = options.log ?? console;
71
+ let stopped = false;
72
+ let timer = null;
73
+ const schedule = (delayMs) => {
74
+ if (stopped) {
75
+ return;
76
+ }
77
+ timer = setTimeout(() => {
78
+ void cycle();
79
+ }, Math.max(MIN_DELAY_MS, delayMs));
80
+ // Never keep the process alive solely for a token renewal.
81
+ timer.unref?.();
82
+ };
83
+ const cycle = async () => {
84
+ if (stopped) {
85
+ return;
86
+ }
87
+ const token = options.getToken() ?? null;
88
+ const claims = decodeClaims(token);
89
+ if (token === null || claims === null
90
+ || !RENEWABLE_TOKEN_TYPES.has(claims.tokenType ?? "")) {
91
+ // Not (yet) a renewable credential — a pre-claim pool member, or a
92
+ // credential class this loop does not own. Park and look again.
93
+ schedule(RECHECK_DELAY_MS);
94
+ return;
95
+ }
96
+ if (claims.expMs === null) {
97
+ // A renewable-class token without an expiry is a mint-side anomaly;
98
+ // renewing "before expiry" is undefined, so park rather than spin.
99
+ log.warn("[sandbox-token-renewal] Credential carries no exp claim; parking");
100
+ schedule(RECHECK_DELAY_MS);
101
+ return;
102
+ }
103
+ const renewAtMs = claims.iatMs !== null
104
+ ? claims.iatMs + (claims.expMs - claims.iatMs) * RENEW_AT_LIFETIME_FRACTION
105
+ : claims.expMs - FALLBACK_RENEW_MARGIN_MS;
106
+ const delayMs = renewAtMs - Date.now();
107
+ if (delayMs > MIN_DELAY_MS) {
108
+ schedule(delayMs);
109
+ return;
110
+ }
111
+ // At or past the renewal point (possibly past expiry after a long pod
112
+ // pause — the attempt is still correct: the server decides).
113
+ try {
114
+ const renewed = await options.renew(token);
115
+ if (renewed) {
116
+ options.applyToken(renewed.token);
117
+ log.log("[sandbox-token-renewal] Sandbox credential renewed");
118
+ // Recompute from the fresh token (its own exp is authoritative).
119
+ schedule(MIN_DELAY_MS);
120
+ }
121
+ else {
122
+ log.warn("[sandbox-token-renewal] Server minted no renewal; will retry");
123
+ schedule(RETRY_DELAY_MS);
124
+ }
125
+ }
126
+ catch (err) {
127
+ log.warn("[sandbox-token-renewal] Renewal failed; will retry: " +
128
+ `${err instanceof Error ? err.message : err}`);
129
+ schedule(RETRY_DELAY_MS);
130
+ }
131
+ };
132
+ void cycle();
133
+ return {
134
+ stop() {
135
+ stopped = true;
136
+ if (timer) {
137
+ clearTimeout(timer);
138
+ timer = null;
139
+ }
140
+ },
141
+ };
142
+ }
143
+ /**
144
+ * Decode the claims this module reads (token_type, iat, exp) from an
145
+ * unverified JWT. Decode-only on purpose: this is the runner's OWN
146
+ * credential, minted by the server it will present it back to —
147
+ * verification happens there.
148
+ */
149
+ function decodeClaims(token) {
150
+ if (!token) {
151
+ return null;
152
+ }
153
+ const parts = token.split(".");
154
+ if (parts.length !== 3) {
155
+ return null;
156
+ }
157
+ try {
158
+ const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf-8"));
159
+ return {
160
+ tokenType: payload.token_type,
161
+ iatMs: typeof payload.iat === "number" ? payload.iat * 1000 : null,
162
+ expMs: typeof payload.exp === "number" ? payload.exp * 1000 : null,
163
+ };
164
+ }
165
+ catch {
166
+ return null;
167
+ }
168
+ }
169
+ //# sourceMappingURL=sandbox-token-renewal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandbox-token-renewal.js","sourceRoot":"","sources":["../src/sandbox-token-renewal.ts"],"names":[],"mappings":"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"}
@@ -44,19 +44,33 @@ export declare class LocalArtifactStorage implements ArtifactStorage {
44
44
  }
45
45
  export declare class ProxyArtifactStorage implements ArtifactStorage {
46
46
  private readonly baseUrl;
47
- private readonly authToken;
48
- constructor(proxyEndpoint: string, authToken: string);
47
+ private readonly authTokenSource;
48
+ constructor(proxyEndpoint: string, authToken: ProxyAuthTokenSource);
49
+ /**
50
+ * Resolve the credential per call rather than pinning the boot token: a
51
+ * cloud sandbox's control-plane token rotates in place (see
52
+ * sandbox-token-renewal.ts), and this storage lives for the pod's whole
53
+ * life — a captured string would silently 401 after the first rotation.
54
+ */
55
+ private get authToken();
49
56
  upload(key: string, content: Buffer, contentType?: string): Promise<string>;
50
57
  getDownloadUrl(key: string): Promise<string>;
51
58
  download(key: string): Promise<Buffer>;
52
59
  exists(key: string): Promise<boolean>;
53
60
  }
61
+ /**
62
+ * The proxy credential, either fixed (a caller-supplied string) or live (a
63
+ * shared mutable ref, read per call — the sandbox token-renewal posture).
64
+ */
65
+ export type ProxyAuthTokenSource = string | {
66
+ readonly current: string | null;
67
+ };
54
68
  export interface ArtifactStorageConfig {
55
69
  readonly type: ArtifactStorageType;
56
70
  readonly localPath: string;
57
71
  readonly localServeUrl: string;
58
72
  readonly proxyEndpoint: string | null;
59
- readonly proxyAuthToken: string | null;
73
+ readonly proxyAuthToken: ProxyAuthTokenSource | null;
60
74
  }
61
75
  export declare function loadArtifactStorageConfig(config: Config): ArtifactStorageConfig;
62
76
  export declare function createArtifactStorage(cfg: ArtifactStorageConfig): ArtifactStorage;
@@ -59,10 +59,21 @@ export class LocalArtifactStorage {
59
59
  // ── Proxy Backend ────────────────────────────────────────────────────
60
60
  export class ProxyArtifactStorage {
61
61
  baseUrl;
62
- authToken;
62
+ authTokenSource;
63
63
  constructor(proxyEndpoint, authToken) {
64
64
  this.baseUrl = `${proxyEndpoint.replace(/\/+$/, "")}/v1/proxy/artifacts`;
65
- this.authToken = authToken;
65
+ this.authTokenSource = authToken;
66
+ }
67
+ /**
68
+ * Resolve the credential per call rather than pinning the boot token: a
69
+ * cloud sandbox's control-plane token rotates in place (see
70
+ * sandbox-token-renewal.ts), and this storage lives for the pod's whole
71
+ * life — a captured string would silently 401 after the first rotation.
72
+ */
73
+ get authToken() {
74
+ return typeof this.authTokenSource === "string"
75
+ ? this.authTokenSource
76
+ : (this.authTokenSource.current ?? "");
66
77
  }
67
78
  async upload(key, content, contentType) {
68
79
  const ct = contentType ?? "application/octet-stream";
@@ -181,7 +192,11 @@ export function loadArtifactStorageConfig(config) {
181
192
  localPath: process.env.LOCAL_ARTIFACT_PATH ?? "/var/stigmer/artifacts",
182
193
  localServeUrl: process.env.LOCAL_ARTIFACT_SERVE_URL ?? "http://localhost:7235",
183
194
  proxyEndpoint: type === "proxy" ? (config.proxyEndpoint ?? null) : null,
184
- proxyAuthToken: type === "proxy" ? (config.stigmerToken ?? null) : null,
195
+ // Prefer the live ref: renewal rotates the token in place and uploads
196
+ // must present the current credential, not the boot one.
197
+ proxyAuthToken: type === "proxy"
198
+ ? (config.stigmerTokenRef ?? config.stigmerToken ?? null)
199
+ : null,
185
200
  };
186
201
  }
187
202
  export function createArtifactStorage(cfg) {
@@ -189,7 +204,10 @@ export function createArtifactStorage(cfg) {
189
204
  if (!cfg.proxyEndpoint) {
190
205
  throw new Error("Proxy artifact storage requires STIGMER_PROXY_ENDPOINT");
191
206
  }
192
- if (!cfg.proxyAuthToken) {
207
+ const tokenAtBoot = typeof cfg.proxyAuthToken === "string"
208
+ ? cfg.proxyAuthToken
209
+ : cfg.proxyAuthToken?.current;
210
+ if (!tokenAtBoot) {
193
211
  throw new Error("Proxy artifact storage requires STIGMER_TOKEN");
194
212
  }
195
213
  return new ProxyArtifactStorage(cfg.proxyEndpoint, cfg.proxyAuthToken);
@@ -1 +1 @@
1
- {"version":3,"file":"artifact-storage.js","sourceRoot":"","sources":["../../src/shared/artifact-storage.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"artifact-storage.js","sourceRoot":"","sources":["../../src/shared/artifact-storage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * The caller identity for MCP server configs — reserved platform env keys
3
+ * that carry the platform-verified "who is calling" into user-defined MCP
4
+ * server headers/args, without ever passing through the model.
5
+ *
6
+ * The identity is a (kind, value) pair with fixed precedence:
7
+ * 1. The channel sender (Meta/Slack-verified, stamped into
8
+ * `SessionSpec.metadata` by the cloud broker — sender-identity.ts is
9
+ * the reader).
10
+ * 2. The session creator (`stigmer_user`) from the Session resource's
11
+ * audit actor — console/CLI sessions have no channel sender, but the
12
+ * platform knows exactly who created the session.
13
+ * 3. The anonymous sentinel — discovery (no session exists) and sessions
14
+ * with no readable creator. Consumers must treat anonymous as a
15
+ * first-class caller: answer tools/list, refuse tool calls.
16
+ *
17
+ * Injection is opt-in by construction: the values enter the env map used
18
+ * for MCP placeholder resolution, and `filterEnvToDeclaredKeys` already
19
+ * restricts every server to the keys it declared in `spec.env`. A server
20
+ * that never declares the reserved keys never receives identity.
21
+ * Declarations MUST be `optional: true` — execution creation validates
22
+ * declared-env completeness in both editions, and these keys have no value
23
+ * until the runner injects them.
24
+ *
25
+ * Trust model: the resulting header is RUNNER-asserted, not signed. It
26
+ * closes the prompt-injection hole (the model cannot influence the value),
27
+ * but the receiving server must pair it with a shared secret and be
28
+ * operated by someone who trusts the runner's network path.
29
+ */
30
+ /** Reserved env key: the identity's kind token. */
31
+ export declare const CALLER_IDENTITY_KIND_ENV_KEY = "STIGMER_CALLER_IDENTITY_KIND";
32
+ /** Reserved env key: the identity's value. */
33
+ export declare const CALLER_IDENTITY_VALUE_ENV_KEY = "STIGMER_CALLER_IDENTITY_VALUE";
34
+ /** Reserved env key: the session the identity was resolved for. */
35
+ export declare const SESSION_ID_ENV_KEY = "STIGMER_SESSION_ID";
36
+ /**
37
+ * Kind token for a platform user (console/CLI session creator). Channel
38
+ * kinds (`whatsapp_phone`, `slack_user_id`, ...) pass through VERBATIM
39
+ * from the cloud broker's metadata — this module never rewrites them.
40
+ */
41
+ export declare const STIGMER_USER_KIND = "stigmer_user";
42
+ /**
43
+ * Kind token for the anonymous caller. Deliberately a real token rather
44
+ * than an absent key: every declared placeholder must resolve in every
45
+ * resolution context, or discovery fails with PlaceholderResolutionError
46
+ * before the server's tools are ever classified.
47
+ */
48
+ export declare const ANONYMOUS_KIND = "anonymous";
49
+ /** The resolved caller identity. */
50
+ export interface CallerIdentity {
51
+ kind: string;
52
+ value: string;
53
+ }
54
+ /** The audit actor shape read from `status.audit.spec_audit.created_by`. */
55
+ export interface SessionCreatorActor {
56
+ id?: string;
57
+ email?: string;
58
+ }
59
+ /** The identity injected when no session context exists (discovery). */
60
+ export declare function anonymousCallerIdentity(): CallerIdentity;
61
+ /**
62
+ * Resolve the caller identity for a session: channel sender first, then
63
+ * the session creator, then anonymous.
64
+ *
65
+ * The creator value prefers email over id: bindings are maintained by
66
+ * humans, and the audit actor's `id` field is historically mixed
67
+ * (identity-account id vs email — see the proto's own @internal note).
68
+ * Binding matchers should compare emails case-insensitively.
69
+ */
70
+ export declare function resolveCallerIdentity(sessionMetadata: Record<string, string> | undefined, creator?: SessionCreatorActor): CallerIdentity;
71
+ /**
72
+ * Return a NEW env map with the reserved caller-identity keys set —
73
+ * platform values are authoritative over same-named user entries (the
74
+ * injectPlatformEnv precedent: a user env var must never be able to
75
+ * impersonate a caller).
76
+ *
77
+ * Call this on the env map handed to MCP resolution ONLY — never on the
78
+ * map that reaches agent subprocess environments. Per-server opt-in is
79
+ * enforced downstream by filterEnvToDeclaredKeys.
80
+ */
81
+ export declare function injectCallerIdentityEnv(envVars: Record<string, string>, identity: CallerIdentity, sessionId: string): Record<string, string>;
82
+ /**
83
+ * Discovery-context injection: the connect workflow resolves the same
84
+ * header templates with no session, so every declared reserved key gets
85
+ * the anonymous sentinel — otherwise a caller-identity-templating server
86
+ * can never be discovered. Gated on the server's declared keys, matching
87
+ * injectPlatformEnv's contract in the discovery activity.
88
+ */
89
+ export declare function injectAnonymousCallerIdentityForDiscovery(declaredEnvKeys: ReadonlySet<string>, envVars: Record<string, string>): Record<string, string>;
@@ -0,0 +1,124 @@
1
+ /**
2
+ * The caller identity for MCP server configs — reserved platform env keys
3
+ * that carry the platform-verified "who is calling" into user-defined MCP
4
+ * server headers/args, without ever passing through the model.
5
+ *
6
+ * The identity is a (kind, value) pair with fixed precedence:
7
+ * 1. The channel sender (Meta/Slack-verified, stamped into
8
+ * `SessionSpec.metadata` by the cloud broker — sender-identity.ts is
9
+ * the reader).
10
+ * 2. The session creator (`stigmer_user`) from the Session resource's
11
+ * audit actor — console/CLI sessions have no channel sender, but the
12
+ * platform knows exactly who created the session.
13
+ * 3. The anonymous sentinel — discovery (no session exists) and sessions
14
+ * with no readable creator. Consumers must treat anonymous as a
15
+ * first-class caller: answer tools/list, refuse tool calls.
16
+ *
17
+ * Injection is opt-in by construction: the values enter the env map used
18
+ * for MCP placeholder resolution, and `filterEnvToDeclaredKeys` already
19
+ * restricts every server to the keys it declared in `spec.env`. A server
20
+ * that never declares the reserved keys never receives identity.
21
+ * Declarations MUST be `optional: true` — execution creation validates
22
+ * declared-env completeness in both editions, and these keys have no value
23
+ * until the runner injects them.
24
+ *
25
+ * Trust model: the resulting header is RUNNER-asserted, not signed. It
26
+ * closes the prompt-injection hole (the model cannot influence the value),
27
+ * but the receiving server must pair it with a shared secret and be
28
+ * operated by someone who trusts the runner's network path.
29
+ */
30
+ import { readSenderIdentity } from "./sender-identity.js";
31
+ /** Reserved env key: the identity's kind token. */
32
+ export const CALLER_IDENTITY_KIND_ENV_KEY = "STIGMER_CALLER_IDENTITY_KIND";
33
+ /** Reserved env key: the identity's value. */
34
+ export const CALLER_IDENTITY_VALUE_ENV_KEY = "STIGMER_CALLER_IDENTITY_VALUE";
35
+ /** Reserved env key: the session the identity was resolved for. */
36
+ export const SESSION_ID_ENV_KEY = "STIGMER_SESSION_ID";
37
+ /**
38
+ * Kind token for a platform user (console/CLI session creator). Channel
39
+ * kinds (`whatsapp_phone`, `slack_user_id`, ...) pass through VERBATIM
40
+ * from the cloud broker's metadata — this module never rewrites them.
41
+ */
42
+ export const STIGMER_USER_KIND = "stigmer_user";
43
+ /**
44
+ * Kind token for the anonymous caller. Deliberately a real token rather
45
+ * than an absent key: every declared placeholder must resolve in every
46
+ * resolution context, or discovery fails with PlaceholderResolutionError
47
+ * before the server's tools are ever classified.
48
+ */
49
+ export const ANONYMOUS_KIND = "anonymous";
50
+ /** The identity injected when no session context exists (discovery). */
51
+ export function anonymousCallerIdentity() {
52
+ return { kind: ANONYMOUS_KIND, value: "" };
53
+ }
54
+ /**
55
+ * Resolve the caller identity for a session: channel sender first, then
56
+ * the session creator, then anonymous.
57
+ *
58
+ * The creator value prefers email over id: bindings are maintained by
59
+ * humans, and the audit actor's `id` field is historically mixed
60
+ * (identity-account id vs email — see the proto's own @internal note).
61
+ * Binding matchers should compare emails case-insensitively.
62
+ */
63
+ export function resolveCallerIdentity(sessionMetadata, creator) {
64
+ const sender = readSenderIdentity(sessionMetadata);
65
+ if (sender) {
66
+ return { kind: sender.kind, value: sender.value };
67
+ }
68
+ const email = creator?.email?.trim();
69
+ const id = creator?.id?.trim();
70
+ const value = email || id;
71
+ if (value) {
72
+ return { kind: STIGMER_USER_KIND, value };
73
+ }
74
+ return anonymousCallerIdentity();
75
+ }
76
+ /**
77
+ * Return a NEW env map with the reserved caller-identity keys set —
78
+ * platform values are authoritative over same-named user entries (the
79
+ * injectPlatformEnv precedent: a user env var must never be able to
80
+ * impersonate a caller).
81
+ *
82
+ * Call this on the env map handed to MCP resolution ONLY — never on the
83
+ * map that reaches agent subprocess environments. Per-server opt-in is
84
+ * enforced downstream by filterEnvToDeclaredKeys.
85
+ */
86
+ export function injectCallerIdentityEnv(envVars, identity, sessionId) {
87
+ const reserved = {
88
+ [CALLER_IDENTITY_KIND_ENV_KEY]: identity.kind,
89
+ [CALLER_IDENTITY_VALUE_ENV_KEY]: identity.value,
90
+ [SESSION_ID_ENV_KEY]: sessionId,
91
+ };
92
+ for (const [key, value] of Object.entries(reserved)) {
93
+ if (key in envVars && envVars[key] !== value) {
94
+ console.info(`Platform env var '${key}' overrides value from ExecutionContext ` +
95
+ `(caller-identity vars are authoritative)`);
96
+ }
97
+ }
98
+ return { ...envVars, ...reserved };
99
+ }
100
+ /**
101
+ * Discovery-context injection: the connect workflow resolves the same
102
+ * header templates with no session, so every declared reserved key gets
103
+ * the anonymous sentinel — otherwise a caller-identity-templating server
104
+ * can never be discovered. Gated on the server's declared keys, matching
105
+ * injectPlatformEnv's contract in the discovery activity.
106
+ */
107
+ export function injectAnonymousCallerIdentityForDiscovery(declaredEnvKeys, envVars) {
108
+ const anonymous = anonymousCallerIdentity();
109
+ const sentinels = {
110
+ [CALLER_IDENTITY_KIND_ENV_KEY]: anonymous.kind,
111
+ [CALLER_IDENTITY_VALUE_ENV_KEY]: anonymous.value,
112
+ [SESSION_ID_ENV_KEY]: "",
113
+ };
114
+ let result;
115
+ for (const [key, value] of Object.entries(sentinels)) {
116
+ if (!declaredEnvKeys.has(key))
117
+ continue;
118
+ if (!result)
119
+ result = { ...envVars };
120
+ result[key] = value;
121
+ }
122
+ return result ?? envVars;
123
+ }
124
+ //# sourceMappingURL=caller-identity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"caller-identity.js","sourceRoot":"","sources":["../../src/shared/caller-identity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * The runner-synthesized channel messaging attachment (proactive-messaging
3
+ * DD-006 D7/D8) — the datastore records attachment's structural twin.
4
+ *
5
+ * When the control plane says an agent serves at least one
6
+ * proactive-messaging channel (the `listMessagingChannels` discovery
7
+ * read, DD-006 D2 — the SAME candidate computation the send
8
+ * authorization runs, so attachment and authority cannot disagree), the
9
+ * runner synthesizes ONE MCP attachment serving `send_channel_message`,
10
+ * and injects the `<available_channel_templates>` prompt section so the
11
+ * model composes template sends in context without spending a tool
12
+ * round (DD-003 D5).
13
+ *
14
+ * Two connection shapes, one roster (the records pattern):
15
+ * - Bridge endpoint configured (cloud): Streamable HTTP against the
16
+ * bridge's /channels route with the execution's own session-scoped
17
+ * credential as the Bearer token.
18
+ * - No bridge endpoint (OSS/local): a spawned `stigmer mcp-server`
19
+ * stdio child with STIGMER_MCP_ROSTER=channels. In practice OSS
20
+ * answers the discovery read with an empty list (DD-006 D3), so
21
+ * this shape only serves local deployments that grow a messaging
22
+ * runtime later — it exists for symmetry with the deployment
23
+ * topology, not for a live OSS path today.
24
+ *
25
+ * Approval-free by construction, and FORCED, not convenient (DD-002
26
+ * D6): both calling surfaces run APPROVAL_MODE_UNATTENDED, where a
27
+ * gated tool resolves as skip-and-adapt — a gated send tool would mean
28
+ * reminders never send. Empty approval maps + no McpServerUsage keep
29
+ * the connect backfill structurally unable to gate it (see
30
+ * synthesized-attachment.ts). Callers inject AFTER resolve + backfill.
31
+ *
32
+ * Failure posture (DD-006 D4): every discovery failure — OSS's empty
33
+ * answer, a registry outage, a control plane predating the RPC
34
+ * (UNIMPLEMENTED), a reach refusal — degrades to honest absence: no
35
+ * tool, no section, execution unharmed.
36
+ */
37
+ import type { ChannelTemplate, MessagingChannel } from "@stigmer/protos/ai/stigmer/agentic/agentchannel/v1/message_io_pb";
38
+ import type { StigmerClient } from "../client/stigmer-client.js";
39
+ import type { ResolvedMcpServer } from "./mcp-resolver.js";
40
+ import { type SynthesizedAttachmentOptions } from "./synthesized-attachment.js";
41
+ /**
42
+ * The synthesized attachment's slug. Reserved: a user McpServer with
43
+ * this slug is shadowed by the synthesized attachment, with a warning.
44
+ * Pinned cross-repo by the mcp-server integration test (the
45
+ * TOOL_CALL_LIMIT precedent).
46
+ */
47
+ export declare const CHANNEL_ATTACHMENT_SLUG = "stigmer-channels";
48
+ /** The bridge route serving the channels-only roster (mcp-server DD-006 D8). */
49
+ export declare const CHANNELS_ROUTE = "/channels";
50
+ /**
51
+ * The most templates the prompt section carries (DD-006 D6): Meta
52
+ * allows hundreds per WABA, and an unbounded section would tax every
53
+ * run's context. Deterministic (name, language) order plus a withheld
54
+ * count keep the agent's behavior independent of registry ordering.
55
+ */
56
+ export declare const TEMPLATE_SECTION_CAP = 30;
57
+ /** One channel plus its sendable approved templates, ready to format. */
58
+ export interface ChannelMessagingInfo {
59
+ channel: MessagingChannel;
60
+ templates: ChannelTemplate[];
61
+ }
62
+ /**
63
+ * The discovery read plus the per-channel template fetch, with the
64
+ * DD-006 D4 failure posture applied: this function NEVER throws — any
65
+ * failure returns an empty list (no tool, no section), because a
66
+ * messaging hiccup must not fail an execution that may not even want
67
+ * to send anything.
68
+ */
69
+ export declare function discoverChannelMessaging(client: StigmerClient, scopedCredential: string | undefined): Promise<ChannelMessagingInfo[]>;
70
+ /**
71
+ * Synthesize the channel messaging attachment. Returns undefined when
72
+ * the agent serves no proactive channel — the attachment exists exactly
73
+ * when the discovery read says so.
74
+ */
75
+ export declare function synthesizeChannelAttachment(channels: ChannelMessagingInfo[], options: SynthesizedAttachmentOptions): ResolvedMcpServer | undefined;
76
+ /**
77
+ * The `<available_channel_templates>` prompt section (DD-003 D5):
78
+ * approved AND sendable templates with their full body text, so the
79
+ * model fills positional placeholders beside the values it composes.
80
+ * Unsendable entries are filtered, not annotated (DD-006 D6 — the
81
+ * console panel is the diagnosis surface, the prompt is a composition
82
+ * aid). Returns "" when nothing survives the filter — the tool alone
83
+ * still serves text sends inside a 24-hour window.
84
+ */
85
+ export declare function formatChannelTemplatesSection(channels: ChannelMessagingInfo[]): string;