@stigmer/runner 3.8.0 → 3.10.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/README.md +2 -2
- package/dist/.build-fingerprint +1 -1
- package/dist/activities/execute-cursor/attachment-resolver.d.ts +16 -0
- package/dist/activities/execute-cursor/attachment-resolver.js +63 -4
- package/dist/activities/execute-cursor/attachment-resolver.js.map +1 -1
- package/dist/activities/execute-cursor/index.d.ts +15 -0
- package/dist/activities/execute-cursor/index.js +73 -11
- package/dist/activities/execute-cursor/index.js.map +1 -1
- package/dist/activities/execute-cursor/prompt-builder.d.ts +14 -1
- package/dist/activities/execute-cursor/prompt-builder.js +11 -2
- package/dist/activities/execute-cursor/prompt-builder.js.map +1 -1
- package/dist/activities/execute-deep-agent/attachment-injector.d.ts +17 -0
- package/dist/activities/execute-deep-agent/attachment-injector.js +34 -4
- package/dist/activities/execute-deep-agent/attachment-injector.js.map +1 -1
- package/dist/activities/execute-deep-agent/hitl.d.ts +15 -7
- package/dist/activities/execute-deep-agent/hitl.js +6 -15
- package/dist/activities/execute-deep-agent/hitl.js.map +1 -1
- package/dist/activities/execute-deep-agent/index.js +4 -1
- package/dist/activities/execute-deep-agent/index.js.map +1 -1
- package/dist/activities/execute-deep-agent/prompt-builder.d.ts +17 -0
- package/dist/activities/execute-deep-agent/prompt-builder.js +13 -2
- package/dist/activities/execute-deep-agent/prompt-builder.js.map +1 -1
- package/dist/activities/execute-deep-agent/setup.js +49 -3
- package/dist/activities/execute-deep-agent/setup.js.map +1 -1
- package/dist/runner-manager.js +14 -0
- package/dist/runner-manager.js.map +1 -1
- package/dist/runner.js +14 -0
- package/dist/runner.js.map +1 -1
- package/dist/shared/artifact-storage.d.ts +10 -0
- package/dist/shared/artifact-storage.js +49 -8
- package/dist/shared/artifact-storage.js.map +1 -1
- package/dist/shared/attachment-vision.d.ts +244 -0
- package/dist/shared/attachment-vision.js +330 -0
- package/dist/shared/attachment-vision.js.map +1 -0
- package/dist/shared/mcp-manager.d.ts +14 -1
- package/dist/shared/mcp-manager.js +20 -21
- package/dist/shared/mcp-manager.js.map +1 -1
- package/dist/shared/model-registry.d.ts +20 -2
- package/dist/shared/model-registry.js +37 -2
- package/dist/shared/model-registry.js.map +1 -1
- package/package.json +3 -3
- package/src/activities/execute-cursor/__tests__/attachment-resolver.test.ts +218 -0
- package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +105 -3
- package/src/activities/execute-cursor/attachment-resolver.ts +97 -4
- package/src/activities/execute-cursor/index.ts +94 -13
- package/src/activities/execute-cursor/prompt-builder.ts +27 -2
- package/src/activities/execute-deep-agent/__tests__/attachment-injector.test.ts +207 -0
- package/src/activities/execute-deep-agent/__tests__/hitl.test.ts +13 -13
- package/src/activities/execute-deep-agent/__tests__/vision-input.test.ts +152 -0
- package/src/activities/execute-deep-agent/attachment-injector.ts +65 -4
- package/src/activities/execute-deep-agent/hitl.ts +14 -19
- package/src/activities/execute-deep-agent/index.ts +4 -5
- package/src/activities/execute-deep-agent/prompt-builder.ts +37 -2
- package/src/activities/execute-deep-agent/setup.ts +58 -3
- package/src/runner-manager.ts +19 -0
- package/src/runner.ts +19 -0
- package/src/shared/__tests__/artifact-storage.test.ts +76 -1
- package/src/shared/__tests__/attachment-vision.test.ts +420 -0
- package/src/shared/__tests__/mcp-manager.test.ts +87 -1
- package/src/shared/__tests__/model-registry.test.ts +71 -0
- package/src/shared/artifact-storage.ts +55 -8
- package/src/shared/attachment-vision.ts +456 -0
- package/src/shared/mcp-manager.ts +22 -22
- package/src/shared/model-registry.ts +50 -2
|
@@ -10,9 +10,22 @@
|
|
|
10
10
|
* resolution time by shared/mcp-transport-guard.ts — servers reaching
|
|
11
11
|
* this manager have already passed it.
|
|
12
12
|
*
|
|
13
|
+
* Stdio env contract (oss#256): a subprocess receives exactly the
|
|
14
|
+
* variables declared in the server's spec.env (resolved upstream by
|
|
15
|
+
* filterEnvToDeclaredKeys) plus the MCP SDK's minimal base environment
|
|
16
|
+
* (HOME, LOGNAME, PATH, SHELL, TERM, USER — getDefaultEnvironment in
|
|
17
|
+
* @modelcontextprotocol/sdk, merged under whatever we pass). The
|
|
18
|
+
* runner's own process env is never passed: it carries runner-internal
|
|
19
|
+
* credentials (STIGMER_TOKEN, STIGMER_RUNNER_HITL_SECRET,
|
|
20
|
+
* CURSOR_API_KEY, LLM provider keys) that no third-party MCP subprocess
|
|
21
|
+
* may see. A declared-empty env and an undeclared env are deliberately
|
|
22
|
+
* equivalent — both yield the SDK base environment.
|
|
23
|
+
*
|
|
13
24
|
* The Cursor execution path does NOT use this manager — it passes MCP
|
|
14
25
|
* configs directly to the Cursor SDK via toCursorMcpConfig(). This
|
|
15
|
-
* manager
|
|
26
|
+
* manager serves LangGraph-based deep agent executions, and discovery
|
|
27
|
+
* (activities/discover-mcp-server.ts) builds its spawn config through
|
|
28
|
+
* toMcpClientConfig too.
|
|
16
29
|
*/
|
|
17
30
|
|
|
18
31
|
import { MultiServerMCPClient } from "@langchain/mcp-adapters";
|
|
@@ -32,11 +45,18 @@ export function toMcpClientConfig(
|
|
|
32
45
|
for (const server of servers) {
|
|
33
46
|
if (server.connectionType === "stdio") {
|
|
34
47
|
if (!server.command) continue;
|
|
48
|
+
if (!server.env || Object.keys(server.env).length === 0) {
|
|
49
|
+
console.log(
|
|
50
|
+
`[MCP] Server '${server.slug}' declares no env — its subprocess ` +
|
|
51
|
+
`starts with the minimal base environment only. Declare variables ` +
|
|
52
|
+
`in the McpServer's spec.env to pass them.`,
|
|
53
|
+
);
|
|
54
|
+
}
|
|
35
55
|
config[server.slug] = {
|
|
36
56
|
transport: "stdio",
|
|
37
57
|
command: server.command,
|
|
38
58
|
args: server.args ?? [],
|
|
39
|
-
env: server.env
|
|
59
|
+
env: server.env,
|
|
40
60
|
cwd: server.cwd,
|
|
41
61
|
};
|
|
42
62
|
} else if (server.connectionType === "http" || server.connectionType === "sse") {
|
|
@@ -91,23 +111,3 @@ export async function connectMcpServers(
|
|
|
91
111
|
|
|
92
112
|
return { client, tools, serverToolMap };
|
|
93
113
|
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Snapshot of process.env as a string-only record (no undefined values).
|
|
97
|
-
* Used as a fallback when an MCP server has no declared env — the
|
|
98
|
-
* subprocess inherits the runner's full environment, matching standard
|
|
99
|
-
* Unix child-process behavior.
|
|
100
|
-
*
|
|
101
|
-
* Without this, @modelcontextprotocol/sdk only passes a restricted
|
|
102
|
-
* whitelist (HOME, PATH, USER, etc.) which drops platform variables
|
|
103
|
-
* like STIGMER_SERVER_ADDRESS.
|
|
104
|
-
*/
|
|
105
|
-
function processEnvAsStrings(): Record<string, string> {
|
|
106
|
-
const env: Record<string, string> = {};
|
|
107
|
-
for (const [key, value] of Object.entries(process.env)) {
|
|
108
|
-
if (value !== undefined) {
|
|
109
|
-
env[key] = value;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
return env;
|
|
113
|
-
}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Model registry — provider lookup
|
|
2
|
+
* Model registry — provider lookup, economy-tier model derivation, and
|
|
3
|
+
* model capability resolution.
|
|
3
4
|
*
|
|
4
5
|
* Fetches the model registry from the runner's control plane (see
|
|
5
6
|
* registry-endpoint.ts for endpoint resolution — same endpoint as
|
|
6
7
|
* model-pricing-data.ts) and uses `costTier` + `harness` fields to
|
|
7
|
-
* dynamically resolve economy-tier models for extraction/summarization
|
|
8
|
+
* dynamically resolve economy-tier models for extraction/summarization,
|
|
9
|
+
* plus `capabilities` catalog metadata for per-model capability lookups
|
|
10
|
+
* (getModelVisionCapability).
|
|
8
11
|
*/
|
|
9
12
|
|
|
10
13
|
import { resolveModelRegistryUrl, buildRegistryHeaders } from "./registry-endpoint.js";
|
|
@@ -22,6 +25,14 @@ interface RegistryModel {
|
|
|
22
25
|
costTier: string;
|
|
23
26
|
harness: string;
|
|
24
27
|
featured: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Tri-state vision capability from the registry's `capabilities` block.
|
|
30
|
+
* The registry serializes `capabilities` only for models whose capabilities
|
|
31
|
+
* have actually been assessed, so `undefined` means "never assessed" —
|
|
32
|
+
* deliberately distinct from an explicit `false` ("assessed as blind").
|
|
33
|
+
* Consumers gate only on the explicit `false` (see attachment-vision.ts).
|
|
34
|
+
*/
|
|
35
|
+
visionCapability?: boolean;
|
|
25
36
|
}
|
|
26
37
|
|
|
27
38
|
let cache: { models: readonly RegistryModel[]; expiresAt: number } | null = null;
|
|
@@ -41,9 +52,20 @@ function parseRegistry(json: unknown): RegistryModel[] {
|
|
|
41
52
|
costTier: (m.costTier as string) ?? "standard",
|
|
42
53
|
harness: (m.harness as string) ?? "native",
|
|
43
54
|
featured: !!m.featured,
|
|
55
|
+
visionCapability: parseVisionCapability(m.capabilities),
|
|
44
56
|
}));
|
|
45
57
|
}
|
|
46
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Extract `capabilities.vision` preserving the tri-state: a missing or
|
|
61
|
+
* malformed `capabilities` block stays `undefined` (never coerced to false).
|
|
62
|
+
*/
|
|
63
|
+
function parseVisionCapability(capabilities: unknown): boolean | undefined {
|
|
64
|
+
if (!capabilities || typeof capabilities !== "object") return undefined;
|
|
65
|
+
const vision = (capabilities as Record<string, unknown>).vision;
|
|
66
|
+
return typeof vision === "boolean" ? vision : undefined;
|
|
67
|
+
}
|
|
68
|
+
|
|
47
69
|
async function fetchRegistry(): Promise<readonly RegistryModel[]> {
|
|
48
70
|
const url = resolveModelRegistryUrl();
|
|
49
71
|
const res = await fetch(url, { headers: buildRegistryHeaders() });
|
|
@@ -211,6 +233,32 @@ export async function resolveToApiModelId(registryId: string): Promise<string> {
|
|
|
211
233
|
return entry.apiModelId ?? registryId;
|
|
212
234
|
}
|
|
213
235
|
|
|
236
|
+
/**
|
|
237
|
+
* Look up a model's vision capability from the registry's `capabilities`
|
|
238
|
+
* catalog metadata. Returns the tri-state the vision policy expects
|
|
239
|
+
* (attachment-vision.ts): `false` only when the registry explicitly says the
|
|
240
|
+
* model cannot see images; `undefined` whenever the answer is unknown —
|
|
241
|
+
* capability never assessed, model not in the registry, registry
|
|
242
|
+
* unreachable, or no concrete model name (the Cursor harness's ""/"default"
|
|
243
|
+
* Auto pool). Callers gate on the explicit `false` only, so every unknown
|
|
244
|
+
* degrades to today's behavior instead of blocking images.
|
|
245
|
+
*
|
|
246
|
+
* Matches by registry `id` OR `apiModelId`: getDefaultModel() hands the
|
|
247
|
+
* deep-agent harness the provider API id, while executionConfig.modelName
|
|
248
|
+
* carries the registry id, so both forms arrive here.
|
|
249
|
+
*/
|
|
250
|
+
export async function getModelVisionCapability(
|
|
251
|
+
modelName: string,
|
|
252
|
+
): Promise<boolean | undefined> {
|
|
253
|
+
if (!modelName || modelName === "default") return undefined;
|
|
254
|
+
|
|
255
|
+
const registry = await getRegistry();
|
|
256
|
+
const entry = registry.find(
|
|
257
|
+
(m) => m.id === modelName || m.apiModelId === modelName,
|
|
258
|
+
);
|
|
259
|
+
return entry?.visionCapability;
|
|
260
|
+
}
|
|
261
|
+
|
|
214
262
|
/** Exposed for testing — resets the in-memory cache. */
|
|
215
263
|
export function _resetRegistryCache(): void {
|
|
216
264
|
cache = null;
|