@stigmer/runner 3.12.8 → 3.12.9
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/execute-cursor/fetch-interceptor.js +29 -16
- package/dist/activities/execute-cursor/fetch-interceptor.js.map +1 -1
- package/dist/activities/execute-cursor/index.d.ts +14 -0
- package/dist/activities/execute-cursor/index.js +55 -5
- package/dist/activities/execute-cursor/index.js.map +1 -1
- package/dist/activities/execute-cursor/message-translator.d.ts +15 -9
- package/dist/activities/execute-cursor/message-translator.js +15 -9
- package/dist/activities/execute-cursor/message-translator.js.map +1 -1
- package/dist/activities/execute-deep-agent/index.js +9 -0
- package/dist/activities/execute-deep-agent/index.js.map +1 -1
- package/dist/activities/execute-deep-agent/setup.d.ts +10 -1
- package/dist/activities/execute-deep-agent/setup.js +20 -3
- package/dist/activities/execute-deep-agent/setup.js.map +1 -1
- package/dist/payload-codecs.d.ts +1 -1
- package/dist/payload-codecs.js +6 -4
- package/dist/payload-codecs.js.map +1 -1
- package/dist/shared/memory-retrieval.d.ts +126 -0
- package/dist/shared/memory-retrieval.js +293 -0
- package/dist/shared/memory-retrieval.js.map +1 -0
- package/dist/shared/runner-credential-keys.js +2 -1
- package/dist/shared/runner-credential-keys.js.map +1 -1
- package/package.json +3 -2
- package/src/__tests__/history-encryption-e2e.test.ts +1 -1
- package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +40 -1
- package/src/activities/execute-cursor/__tests__/fetch-interceptor.test.ts +49 -15
- package/src/activities/execute-cursor/fetch-interceptor.ts +37 -16
- package/src/activities/execute-cursor/index.ts +58 -5
- package/src/activities/execute-cursor/message-translator.ts +15 -9
- package/src/activities/execute-deep-agent/index.ts +10 -0
- package/src/activities/execute-deep-agent/setup.ts +34 -6
- package/src/payload-codecs.ts +12 -9
- package/src/shared/__tests__/memory-retrieval.test.ts +310 -0
- package/src/shared/memory-retrieval.ts +383 -0
- package/src/shared/runner-credential-keys.ts +2 -1
- package/dist/claimcheck/compressor.d.ts +0 -2
- package/dist/claimcheck/compressor.js +0 -8
- package/dist/claimcheck/compressor.js.map +0 -1
- package/dist/claimcheck/config.d.ts +0 -7
- package/dist/claimcheck/config.js +0 -10
- package/dist/claimcheck/config.js.map +0 -1
- package/dist/claimcheck/index.d.ts +0 -3
- package/dist/claimcheck/index.js +0 -4
- package/dist/claimcheck/index.js.map +0 -1
- package/dist/claimcheck/payload-codec.d.ts +0 -23
- package/dist/claimcheck/payload-codec.js +0 -105
- package/dist/claimcheck/payload-codec.js.map +0 -1
- package/dist/encryption/config.d.ts +0 -64
- package/dist/encryption/config.js +0 -113
- package/dist/encryption/config.js.map +0 -1
- package/dist/encryption/index.d.ts +0 -3
- package/dist/encryption/index.js +0 -3
- package/dist/encryption/index.js.map +0 -1
- package/dist/encryption/payload-codec.d.ts +0 -41
- package/dist/encryption/payload-codec.js +0 -130
- package/dist/encryption/payload-codec.js.map +0 -1
- package/src/__tests__/claimcheck-codec.test.ts +0 -256
- package/src/__tests__/encryption-codec.test.ts +0 -287
- package/src/__tests__/fixtures/encrypted-payload-fixture.json +0 -15
- package/src/claimcheck/compressor.ts +0 -9
- package/src/claimcheck/config.ts +0 -20
- package/src/claimcheck/index.ts +0 -3
- package/src/claimcheck/payload-codec.ts +0 -139
- package/src/encryption/config.ts +0 -161
- package/src/encryption/index.ts +0 -3
- package/src/encryption/payload-codec.ts +0 -152
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Semantic selection of recalled memories (stigmer/stigmer#293 Phase 3a,
|
|
3
|
+
* DD-008): when a subject's confirmed-fact set outgrows what wholesale
|
|
4
|
+
* injection should carry, select the most relevant facts for THIS
|
|
5
|
+
* execution instead of injecting everything.
|
|
6
|
+
*
|
|
7
|
+
* Sibling of recalled-memories.ts (which owns presentation) — this module
|
|
8
|
+
* owns SELECTION: which subset of the server-composed candidate set
|
|
9
|
+
* (`spec.recalled_memories`, the auditable snapshot both editions' compose
|
|
10
|
+
* steps stamp) actually rides the prompt. The compose steps never change;
|
|
11
|
+
* selection is a runner concern because the runner owns prompt assembly,
|
|
12
|
+
* provider credentials, and the metered proxy lane (DD-008 D1 — the
|
|
13
|
+
* titling-convergence doctrine: control-plane-adjacent LLM work runs once,
|
|
14
|
+
* in the shared runner, for both editions).
|
|
15
|
+
*
|
|
16
|
+
* Mechanism (DD-008 D2/D3): embed-on-read, no stored vectors anywhere.
|
|
17
|
+
* Selection activates ONLY above RETRIEVAL_K candidates; below that,
|
|
18
|
+
* top-k degenerates to wholesale, so no embeddings call is made and the
|
|
19
|
+
* shipped Phase 2 path runs untouched. When active: ONE batched
|
|
20
|
+
* embeddings call (query + all candidates), in-process cosine ranking,
|
|
21
|
+
* top-k by relevance, presented in snapshot order (relevance order would
|
|
22
|
+
* carry no information the model needs and would churn the prompt prefix).
|
|
23
|
+
* The query is the execution's `spec.message` — the current turn.
|
|
24
|
+
*
|
|
25
|
+
* The audit contract (DD-008 D5): the selection outcome is recorded in a
|
|
26
|
+
* runner-owned `RecalledMemoriesReport` on the execution status (the
|
|
27
|
+
* streaming_usage posture — one writer, written at prompt build). A report
|
|
28
|
+
* is returned whenever facts are injected, wholesale or selected; when
|
|
29
|
+
* nothing is injected (recall absent/disabled/empty) there is no report —
|
|
30
|
+
* absent report = wholesale, true by construction, so pre-3a executions
|
|
31
|
+
* read identically.
|
|
32
|
+
*
|
|
33
|
+
* Written-once across re-invocations: the same execution's prompt is
|
|
34
|
+
* rebuilt on approval resume (native) and fresh-agent recovery (cursor).
|
|
35
|
+
* Re-running selection there could pick a DIFFERENT subset mid-execution —
|
|
36
|
+
* so when the loaded execution already carries a report, this module
|
|
37
|
+
* REPLAYS it (selected ids resolved against the snapshot, or wholesale
|
|
38
|
+
* for a selection_active=false report) instead of re-embedding. Selection
|
|
39
|
+
* is computed at most once per execution, by construction.
|
|
40
|
+
*
|
|
41
|
+
* Failure posture: selection is an optimization. ANY failure — no
|
|
42
|
+
* embedder, HTTP error, timeout, malformed response — degrades to
|
|
43
|
+
* wholesale injection with a selection_active=false report, never a
|
|
44
|
+
* failed or degraded execution (DD-008 D3). Deployments with no
|
|
45
|
+
* embeddings-capable credential (Anthropic-only, Cursor-only OSS) run
|
|
46
|
+
* Phase 2 behavior unchanged, forever.
|
|
47
|
+
*/
|
|
48
|
+
import type { RecalledMemories } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/spec_pb";
|
|
49
|
+
import { type RecalledMemoriesReport } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
|
|
50
|
+
import type { RecalledMemoriesContent } from "./recalled-memories.js";
|
|
51
|
+
/**
|
|
52
|
+
* Selection activates only when the candidate set EXCEEDS this many facts;
|
|
53
|
+
* at or below it, top-k degenerates to wholesale and no embeddings call is
|
|
54
|
+
* made. 20 is comfortably above the dozens-scale where wholesale is fine
|
|
55
|
+
* (activation is rare) and comfortably below the 100-record cap (activation
|
|
56
|
+
* is meaningful): at 500-char facts, 20 facts ≈ 10KB of prompt. One
|
|
57
|
+
* constant, one place, deliberately not adaptive or per-org configurable
|
|
58
|
+
* in v1 (DD-008 D3).
|
|
59
|
+
*/
|
|
60
|
+
export declare const RETRIEVAL_K = 20;
|
|
61
|
+
/**
|
|
62
|
+
* The v1 embedder (DD-008 D4). OpenAI-only: resolved through the Stigmer
|
|
63
|
+
* proxy when one is configured (cloud — platform key, metered), else the
|
|
64
|
+
* operator's direct OpenAI key (OSS). NOTE: llm-proxy's `inferProvider`
|
|
65
|
+
* does not know the `text-*` prefix — this module never infers; the
|
|
66
|
+
* provider is fixed alongside the model.
|
|
67
|
+
*/
|
|
68
|
+
export declare const EMBEDDING_MODEL = "text-embedding-3-small";
|
|
69
|
+
/**
|
|
70
|
+
* Upper bound on the query text sent to the embedder. Facts are write-time
|
|
71
|
+
* capped at 500 chars, but the query is `spec.message` — unbounded. A giant
|
|
72
|
+
* pasted message would blow the embedder's per-input token limit (8192 for
|
|
73
|
+
* text-embedding-3-small) and 400 the WHOLE batched call, silently forcing
|
|
74
|
+
* wholesale on exactly the executions where selection matters. 20K chars
|
|
75
|
+
* sits safely under the limit at worst-case chars-per-token; selection
|
|
76
|
+
* intent is dominated by the message head, and a truncated query beats no
|
|
77
|
+
* selection.
|
|
78
|
+
*/
|
|
79
|
+
export declare const QUERY_MAX_CHARS = 20000;
|
|
80
|
+
/**
|
|
81
|
+
* One batched embeddings call: one vector per input, in input order.
|
|
82
|
+
* The seam unit tests inject through, and the boundary a stored-vector
|
|
83
|
+
* optimization would slot behind if caps ever grow (DD-008 D2).
|
|
84
|
+
*/
|
|
85
|
+
export type EmbedFn = (inputs: readonly string[]) => Promise<number[][]>;
|
|
86
|
+
export interface MemoryRetrievalOptions {
|
|
87
|
+
/** Null/undefined when the deployment has no proxy (direct mode). */
|
|
88
|
+
readonly proxyEndpoint: string | null | undefined;
|
|
89
|
+
/** Bearer for proxy mode; unused in direct mode. */
|
|
90
|
+
readonly stigmerToken: string | null | undefined;
|
|
91
|
+
/** Scopes the proxied call for FGA authorization and billing attribution. */
|
|
92
|
+
readonly executionId: string;
|
|
93
|
+
/**
|
|
94
|
+
* The report a PREVIOUS invocation of this same execution recorded, if
|
|
95
|
+
* any (`execution.status.recalled_memories_report`). Presence replays
|
|
96
|
+
* the recorded outcome instead of re-selecting — the written-once rule.
|
|
97
|
+
*/
|
|
98
|
+
readonly priorReport?: RecalledMemoriesReport;
|
|
99
|
+
/** Test seam; defaults to the proxy/direct embedder resolution. */
|
|
100
|
+
readonly embed?: EmbedFn;
|
|
101
|
+
}
|
|
102
|
+
export interface MemorySelectionResult {
|
|
103
|
+
/**
|
|
104
|
+
* The facts to inject, in snapshot order — undefined when recall is
|
|
105
|
+
* absent, disabled, or empty (render nothing, exactly the
|
|
106
|
+
* readRecalledMemories contract).
|
|
107
|
+
*/
|
|
108
|
+
readonly content: RecalledMemoriesContent | undefined;
|
|
109
|
+
/**
|
|
110
|
+
* The injection outcome to stamp on the execution status. Undefined
|
|
111
|
+
* exactly when `content` is undefined: no injection, no report.
|
|
112
|
+
*/
|
|
113
|
+
readonly report: RecalledMemoriesReport | undefined;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Select the facts to inject for one execution.
|
|
117
|
+
*
|
|
118
|
+
* This is the ONE entry point both harnesses call at prompt build, replacing
|
|
119
|
+
* their direct `readRecalledMemories` reads on the injection path (the read
|
|
120
|
+
* function remains the presentation-side authority; this module reads the
|
|
121
|
+
* proto itself because selection needs `memory_id`, which the render
|
|
122
|
+
* boundary deliberately strips).
|
|
123
|
+
*
|
|
124
|
+
* Never throws: every failure path returns wholesale.
|
|
125
|
+
*/
|
|
126
|
+
export declare function selectRecalledFacts(recalled: RecalledMemories | undefined, queryText: string, options: MemoryRetrievalOptions): Promise<MemorySelectionResult>;
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Semantic selection of recalled memories (stigmer/stigmer#293 Phase 3a,
|
|
3
|
+
* DD-008): when a subject's confirmed-fact set outgrows what wholesale
|
|
4
|
+
* injection should carry, select the most relevant facts for THIS
|
|
5
|
+
* execution instead of injecting everything.
|
|
6
|
+
*
|
|
7
|
+
* Sibling of recalled-memories.ts (which owns presentation) — this module
|
|
8
|
+
* owns SELECTION: which subset of the server-composed candidate set
|
|
9
|
+
* (`spec.recalled_memories`, the auditable snapshot both editions' compose
|
|
10
|
+
* steps stamp) actually rides the prompt. The compose steps never change;
|
|
11
|
+
* selection is a runner concern because the runner owns prompt assembly,
|
|
12
|
+
* provider credentials, and the metered proxy lane (DD-008 D1 — the
|
|
13
|
+
* titling-convergence doctrine: control-plane-adjacent LLM work runs once,
|
|
14
|
+
* in the shared runner, for both editions).
|
|
15
|
+
*
|
|
16
|
+
* Mechanism (DD-008 D2/D3): embed-on-read, no stored vectors anywhere.
|
|
17
|
+
* Selection activates ONLY above RETRIEVAL_K candidates; below that,
|
|
18
|
+
* top-k degenerates to wholesale, so no embeddings call is made and the
|
|
19
|
+
* shipped Phase 2 path runs untouched. When active: ONE batched
|
|
20
|
+
* embeddings call (query + all candidates), in-process cosine ranking,
|
|
21
|
+
* top-k by relevance, presented in snapshot order (relevance order would
|
|
22
|
+
* carry no information the model needs and would churn the prompt prefix).
|
|
23
|
+
* The query is the execution's `spec.message` — the current turn.
|
|
24
|
+
*
|
|
25
|
+
* The audit contract (DD-008 D5): the selection outcome is recorded in a
|
|
26
|
+
* runner-owned `RecalledMemoriesReport` on the execution status (the
|
|
27
|
+
* streaming_usage posture — one writer, written at prompt build). A report
|
|
28
|
+
* is returned whenever facts are injected, wholesale or selected; when
|
|
29
|
+
* nothing is injected (recall absent/disabled/empty) there is no report —
|
|
30
|
+
* absent report = wholesale, true by construction, so pre-3a executions
|
|
31
|
+
* read identically.
|
|
32
|
+
*
|
|
33
|
+
* Written-once across re-invocations: the same execution's prompt is
|
|
34
|
+
* rebuilt on approval resume (native) and fresh-agent recovery (cursor).
|
|
35
|
+
* Re-running selection there could pick a DIFFERENT subset mid-execution —
|
|
36
|
+
* so when the loaded execution already carries a report, this module
|
|
37
|
+
* REPLAYS it (selected ids resolved against the snapshot, or wholesale
|
|
38
|
+
* for a selection_active=false report) instead of re-embedding. Selection
|
|
39
|
+
* is computed at most once per execution, by construction.
|
|
40
|
+
*
|
|
41
|
+
* Failure posture: selection is an optimization. ANY failure — no
|
|
42
|
+
* embedder, HTTP error, timeout, malformed response — degrades to
|
|
43
|
+
* wholesale injection with a selection_active=false report, never a
|
|
44
|
+
* failed or degraded execution (DD-008 D3). Deployments with no
|
|
45
|
+
* embeddings-capable credential (Anthropic-only, Cursor-only OSS) run
|
|
46
|
+
* Phase 2 behavior unchanged, forever.
|
|
47
|
+
*/
|
|
48
|
+
import { create } from "@bufbuild/protobuf";
|
|
49
|
+
import { RecalledMemoriesReportSchema, } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
|
|
50
|
+
import { resolveProxyBaseUrl, buildProxyHeaders } from "./llm-proxy.js";
|
|
51
|
+
import { checkDirectCredentials } from "./llm-backend.js";
|
|
52
|
+
import { getRunnerSecret } from "./runner-credential-store.js";
|
|
53
|
+
/**
|
|
54
|
+
* Selection activates only when the candidate set EXCEEDS this many facts;
|
|
55
|
+
* at or below it, top-k degenerates to wholesale and no embeddings call is
|
|
56
|
+
* made. 20 is comfortably above the dozens-scale where wholesale is fine
|
|
57
|
+
* (activation is rare) and comfortably below the 100-record cap (activation
|
|
58
|
+
* is meaningful): at 500-char facts, 20 facts ≈ 10KB of prompt. One
|
|
59
|
+
* constant, one place, deliberately not adaptive or per-org configurable
|
|
60
|
+
* in v1 (DD-008 D3).
|
|
61
|
+
*/
|
|
62
|
+
export const RETRIEVAL_K = 20;
|
|
63
|
+
/**
|
|
64
|
+
* The v1 embedder (DD-008 D4). OpenAI-only: resolved through the Stigmer
|
|
65
|
+
* proxy when one is configured (cloud — platform key, metered), else the
|
|
66
|
+
* operator's direct OpenAI key (OSS). NOTE: llm-proxy's `inferProvider`
|
|
67
|
+
* does not know the `text-*` prefix — this module never infers; the
|
|
68
|
+
* provider is fixed alongside the model.
|
|
69
|
+
*/
|
|
70
|
+
export const EMBEDDING_MODEL = "text-embedding-3-small";
|
|
71
|
+
/**
|
|
72
|
+
* Upper bound on the query text sent to the embedder. Facts are write-time
|
|
73
|
+
* capped at 500 chars, but the query is `spec.message` — unbounded. A giant
|
|
74
|
+
* pasted message would blow the embedder's per-input token limit (8192 for
|
|
75
|
+
* text-embedding-3-small) and 400 the WHOLE batched call, silently forcing
|
|
76
|
+
* wholesale on exactly the executions where selection matters. 20K chars
|
|
77
|
+
* sits safely under the limit at worst-case chars-per-token; selection
|
|
78
|
+
* intent is dominated by the message head, and a truncated query beats no
|
|
79
|
+
* selection.
|
|
80
|
+
*/
|
|
81
|
+
export const QUERY_MAX_CHARS = 20_000;
|
|
82
|
+
/**
|
|
83
|
+
* Bound on the single embeddings round trip. Generous relative to the
|
|
84
|
+
* observed 200–400ms typical latency: this exists to keep a hung
|
|
85
|
+
* connection from stalling prompt build, not to race the provider.
|
|
86
|
+
*/
|
|
87
|
+
const EMBED_TIMEOUT_MS = 15_000;
|
|
88
|
+
/** The OpenAI SDK-default base, used only in direct (unproxied) mode. */
|
|
89
|
+
const DIRECT_OPENAI_BASE_URL = "https://api.openai.com/v1";
|
|
90
|
+
/**
|
|
91
|
+
* Select the facts to inject for one execution.
|
|
92
|
+
*
|
|
93
|
+
* This is the ONE entry point both harnesses call at prompt build, replacing
|
|
94
|
+
* their direct `readRecalledMemories` reads on the injection path (the read
|
|
95
|
+
* function remains the presentation-side authority; this module reads the
|
|
96
|
+
* proto itself because selection needs `memory_id`, which the render
|
|
97
|
+
* boundary deliberately strips).
|
|
98
|
+
*
|
|
99
|
+
* Never throws: every failure path returns wholesale.
|
|
100
|
+
*/
|
|
101
|
+
export async function selectRecalledFacts(recalled, queryText, options) {
|
|
102
|
+
const candidates = readCandidates(recalled);
|
|
103
|
+
if (candidates.length === 0) {
|
|
104
|
+
return { content: undefined, report: undefined };
|
|
105
|
+
}
|
|
106
|
+
// Written-once: a prior invocation of this execution already decided.
|
|
107
|
+
if (options.priorReport !== undefined) {
|
|
108
|
+
const replayed = replayReport(candidates, options.priorReport);
|
|
109
|
+
if (replayed !== undefined) {
|
|
110
|
+
return replayed;
|
|
111
|
+
}
|
|
112
|
+
// Unreplayable (recorded ids missing from the immutable snapshot —
|
|
113
|
+
// structurally impossible, defended anyway): fall through and select
|
|
114
|
+
// fresh rather than inject nothing.
|
|
115
|
+
log(`prior report for execution ${options.executionId} did not resolve ` +
|
|
116
|
+
`against the snapshot; re-selecting`);
|
|
117
|
+
}
|
|
118
|
+
if (candidates.length <= RETRIEVAL_K) {
|
|
119
|
+
return wholesale(candidates);
|
|
120
|
+
}
|
|
121
|
+
const embed = options.embed ?? resolveEmbedder(options);
|
|
122
|
+
if (embed === undefined) {
|
|
123
|
+
// No embeddings-capable credential: the recorded no-embedder posture
|
|
124
|
+
// (DD-008 D4) — Phase 2 behavior, honestly reported.
|
|
125
|
+
return wholesale(candidates);
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
const query = queryText.slice(0, QUERY_MAX_CHARS);
|
|
129
|
+
const vectors = await embed([query, ...candidates.map((c) => c.content)]);
|
|
130
|
+
if (vectors.length !== candidates.length + 1) {
|
|
131
|
+
throw new Error(`embedder returned ${vectors.length} vectors for ` +
|
|
132
|
+
`${candidates.length + 1} inputs`);
|
|
133
|
+
}
|
|
134
|
+
const [queryVector, ...factVectors] = vectors;
|
|
135
|
+
const selected = topKBySimilarity(queryVector, factVectors, RETRIEVAL_K);
|
|
136
|
+
return {
|
|
137
|
+
content: { facts: selected.map((i) => candidates[i].content) },
|
|
138
|
+
report: create(RecalledMemoriesReportSchema, {
|
|
139
|
+
selectionActive: true,
|
|
140
|
+
injectedMemoryIds: selected.map((i) => candidates[i].memoryId),
|
|
141
|
+
embeddingModel: EMBEDDING_MODEL,
|
|
142
|
+
}),
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
log(`selection failed for execution ${options.executionId}, degrading to ` +
|
|
147
|
+
`wholesale: ${err instanceof Error ? err.message : String(err)}`);
|
|
148
|
+
return wholesale(candidates);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* The snapshot's renderable candidates, in snapshot order. Same semantics
|
|
153
|
+
* as readRecalledMemories (disabled → none; blank contents dropped
|
|
154
|
+
* defensively) but keeping `memory_id` — the report's audit link.
|
|
155
|
+
*/
|
|
156
|
+
function readCandidates(recalled) {
|
|
157
|
+
if (!recalled?.enabled) {
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
return (recalled.facts ?? [])
|
|
161
|
+
.map((fact) => ({
|
|
162
|
+
memoryId: fact.memoryId ?? "",
|
|
163
|
+
content: fact.content?.trim() ?? "",
|
|
164
|
+
}))
|
|
165
|
+
.filter((c) => c.content !== "");
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Replay a previously recorded outcome so a re-invocation injects exactly
|
|
169
|
+
* what the first invocation did. A selection_active=false report replays
|
|
170
|
+
* as wholesale (including the case where a transient embed failure was
|
|
171
|
+
* recorded — retrying could select a subset and diverge the prompt).
|
|
172
|
+
* Returns undefined when a recorded id no longer resolves.
|
|
173
|
+
*/
|
|
174
|
+
function replayReport(candidates, prior) {
|
|
175
|
+
if (!prior.selectionActive) {
|
|
176
|
+
return wholesale(candidates);
|
|
177
|
+
}
|
|
178
|
+
const byId = new Map(candidates.map((c) => [c.memoryId, c.content]));
|
|
179
|
+
const facts = [];
|
|
180
|
+
for (const id of prior.injectedMemoryIds) {
|
|
181
|
+
const content = byId.get(id);
|
|
182
|
+
if (content === undefined) {
|
|
183
|
+
return undefined;
|
|
184
|
+
}
|
|
185
|
+
facts.push(content);
|
|
186
|
+
}
|
|
187
|
+
if (facts.length === 0) {
|
|
188
|
+
return undefined;
|
|
189
|
+
}
|
|
190
|
+
return { content: { facts }, report: prior };
|
|
191
|
+
}
|
|
192
|
+
/** Wholesale injection of the full candidate set, honestly reported. */
|
|
193
|
+
function wholesale(candidates) {
|
|
194
|
+
return {
|
|
195
|
+
content: { facts: candidates.map((c) => c.content) },
|
|
196
|
+
report: create(RecalledMemoriesReportSchema, { selectionActive: false }),
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* The credential lanes, in the platform's standing precedence (the
|
|
201
|
+
* titling-lane idiom): proxy when configured — the runner authenticates
|
|
202
|
+
* with its Stigmer token and the proxy owns the provider key — else the
|
|
203
|
+
* operator's direct OpenAI key, else no embedder.
|
|
204
|
+
*/
|
|
205
|
+
function resolveEmbedder(options) {
|
|
206
|
+
if (options.proxyEndpoint) {
|
|
207
|
+
return fetchEmbedder(resolveProxyBaseUrl(options.proxyEndpoint, "openai"), buildProxyHeaders(options.stigmerToken ?? "", {
|
|
208
|
+
executionId: options.executionId,
|
|
209
|
+
}));
|
|
210
|
+
}
|
|
211
|
+
if (checkDirectCredentials("openai") === null) {
|
|
212
|
+
return fetchEmbedder(DIRECT_OPENAI_BASE_URL, {
|
|
213
|
+
Authorization: `Bearer ${getRunnerSecret("OPENAI_API_KEY") ?? ""}`,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
return undefined;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* The real embedder: one POST {base}/embeddings. A plain typed fetch, not
|
|
220
|
+
* LangChain's OpenAIEmbeddings — the SDK wrapper discards the response
|
|
221
|
+
* `usage` block and adds nothing over a single request. Proxy-side
|
|
222
|
+
* metering reads the JSON usage from the relayed body.
|
|
223
|
+
*/
|
|
224
|
+
function fetchEmbedder(baseUrl, headers) {
|
|
225
|
+
return async (inputs) => {
|
|
226
|
+
const response = await fetch(`${baseUrl}/embeddings`, {
|
|
227
|
+
method: "POST",
|
|
228
|
+
headers: { ...headers, "Content-Type": "application/json" },
|
|
229
|
+
body: JSON.stringify({ model: EMBEDDING_MODEL, input: inputs }),
|
|
230
|
+
signal: AbortSignal.timeout(EMBED_TIMEOUT_MS),
|
|
231
|
+
});
|
|
232
|
+
if (!response.ok) {
|
|
233
|
+
const body = await response.text().catch(() => "");
|
|
234
|
+
throw new Error(`embeddings request failed: HTTP ${response.status} ${body.slice(0, 300)}`);
|
|
235
|
+
}
|
|
236
|
+
const parsed = (await response.json());
|
|
237
|
+
if (!Array.isArray(parsed.data)) {
|
|
238
|
+
throw new Error("embeddings response carries no data array");
|
|
239
|
+
}
|
|
240
|
+
// Place by the response's own index field — the API documents input
|
|
241
|
+
// order, but the contract names the index as authoritative.
|
|
242
|
+
const vectors = new Array(inputs.length);
|
|
243
|
+
for (const item of parsed.data) {
|
|
244
|
+
const index = item.index ?? -1;
|
|
245
|
+
if (index < 0 || index >= inputs.length || !Array.isArray(item.embedding)) {
|
|
246
|
+
throw new Error("embeddings response entry is malformed");
|
|
247
|
+
}
|
|
248
|
+
vectors[index] = item.embedding;
|
|
249
|
+
}
|
|
250
|
+
if (vectors.some((v) => v === undefined)) {
|
|
251
|
+
throw new Error("embeddings response is missing entries");
|
|
252
|
+
}
|
|
253
|
+
return vectors;
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Indices of the top-k facts by cosine similarity to the query, returned
|
|
258
|
+
* ASCENDING — i.e. re-sorted to snapshot order (DD-008 D3: selection is by
|
|
259
|
+
* relevance, presentation stays oldest-first). Ties break toward the lower
|
|
260
|
+
* snapshot index, so equal scores never reorder across invocations.
|
|
261
|
+
*/
|
|
262
|
+
function topKBySimilarity(queryVector, factVectors, k) {
|
|
263
|
+
return factVectors
|
|
264
|
+
.map((vector, index) => ({ index, score: cosineSimilarity(queryVector, vector) }))
|
|
265
|
+
.sort((a, b) => b.score - a.score || a.index - b.index)
|
|
266
|
+
.slice(0, k)
|
|
267
|
+
.map((entry) => entry.index)
|
|
268
|
+
.sort((a, b) => a - b);
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Plain cosine. OpenAI embeddings arrive unit-normalized (a dot product
|
|
272
|
+
* would suffice today), but normalizing here keeps ranking correct under
|
|
273
|
+
* any future embedder without a silent provider assumption.
|
|
274
|
+
*/
|
|
275
|
+
function cosineSimilarity(a, b) {
|
|
276
|
+
let dot = 0;
|
|
277
|
+
let normA = 0;
|
|
278
|
+
let normB = 0;
|
|
279
|
+
const length = Math.min(a.length, b.length);
|
|
280
|
+
for (let i = 0; i < length; i++) {
|
|
281
|
+
dot += a[i] * b[i];
|
|
282
|
+
normA += a[i] * a[i];
|
|
283
|
+
normB += b[i] * b[i];
|
|
284
|
+
}
|
|
285
|
+
if (normA === 0 || normB === 0) {
|
|
286
|
+
return 0;
|
|
287
|
+
}
|
|
288
|
+
return dot / (Math.sqrt(normA) * Math.sqrt(normB));
|
|
289
|
+
}
|
|
290
|
+
function log(msg) {
|
|
291
|
+
console.warn(`[memory-retrieval] ${msg}`);
|
|
292
|
+
}
|
|
293
|
+
//# sourceMappingURL=memory-retrieval.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-retrieval.js","sourceRoot":"","sources":["../../src/shared/memory-retrieval.ts"],"names":[],"mappings":"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"}
|
|
@@ -62,7 +62,8 @@ export const RUNNER_CREDENTIAL_ENV_KEYS = [
|
|
|
62
62
|
* rotation bookkeeping, not secrets.
|
|
63
63
|
*/
|
|
64
64
|
export const RUNNER_ENCRYPTION_ENV_KEYS = [
|
|
65
|
-
// Temporal payload-encryption keys (
|
|
65
|
+
// Temporal payload-encryption keys (@stigmer/temporal-codecs' encryption
|
|
66
|
+
// config, read through the injected getRunnerSecret). An agent that
|
|
66
67
|
// reads these could decrypt the runner's Temporal history payloads.
|
|
67
68
|
"STIGMER_PAYLOAD_ENCRYPTION_KEY",
|
|
68
69
|
"STIGMER_PAYLOAD_ENCRYPTION_SECONDARY_KEY",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner-credential-keys.js","sourceRoot":"","sources":["../../src/shared/runner-credential-keys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAsB;IAC3D,wEAAwE;IACxE,iDAAiD;IACjD,4BAA4B;IAC5B,+DAA+D;IAC/D,sEAAsE;IACtE,eAAe;IACf,gEAAgE;IAChE,iDAAiD;IACjD,oBAAoB;IACpB,wEAAwE;IACxE,iCAAiC;IACjC,gBAAgB;IAChB,sEAAsE;IACtE,mBAAmB;IACnB,mEAAmE;IACnE,gBAAgB;IAChB,kDAAkD;IAClD,2BAA2B;IAC3B,iEAAiE;IACjE,0DAA0D;IAC1D,0BAA0B;CAC3B,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAsB;IAC3D,yEAAyE;IACzE,oEAAoE;IACpE,gCAAgC;IAChC,0CAA0C;CAC3C,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAsB;IACvD,GAAG,0BAA0B;IAC7B,GAAG,0BAA0B;CAC9B,CAAC"}
|
|
1
|
+
{"version":3,"file":"runner-credential-keys.js","sourceRoot":"","sources":["../../src/shared/runner-credential-keys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAsB;IAC3D,wEAAwE;IACxE,iDAAiD;IACjD,4BAA4B;IAC5B,+DAA+D;IAC/D,sEAAsE;IACtE,eAAe;IACf,gEAAgE;IAChE,iDAAiD;IACjD,oBAAoB;IACpB,wEAAwE;IACxE,iCAAiC;IACjC,gBAAgB;IAChB,sEAAsE;IACtE,mBAAmB;IACnB,mEAAmE;IACnE,gBAAgB;IAChB,kDAAkD;IAClD,2BAA2B;IAC3B,iEAAiE;IACjE,0DAA0D;IAC1D,0BAA0B;CAC3B,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAsB;IAC3D,yEAAyE;IACzE,oEAAoE;IACpE,oEAAoE;IACpE,gCAAgC;IAChC,0CAA0C;CAC3C,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAsB;IACvD,GAAG,0BAA0B;IAC7B,GAAG,0BAA0B;CAC9B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stigmer/runner",
|
|
3
|
-
"version": "3.12.
|
|
3
|
+
"version": "3.12.9",
|
|
4
4
|
"description": "Embeddable Temporal worker for the Stigmer AI agent platform — handles agent execution, workflow orchestration, and MCP server management",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -94,7 +94,8 @@
|
|
|
94
94
|
"@opentelemetry/sdk-metrics": "^2.0.0",
|
|
95
95
|
"@opentelemetry/sdk-trace-base": "^2.0.0",
|
|
96
96
|
"@opentelemetry/sdk-trace-node": "^2.0.0",
|
|
97
|
-
"@stigmer/protos": "3.12.
|
|
97
|
+
"@stigmer/protos": "3.12.9",
|
|
98
|
+
"@stigmer/temporal-codecs": "3.12.9",
|
|
98
99
|
"@temporalio/activity": "1.16.2",
|
|
99
100
|
"@temporalio/common": "1.16.2",
|
|
100
101
|
"@temporalio/interceptors-opentelemetry": "1.16.2",
|
|
@@ -25,7 +25,7 @@ import { join, dirname } from "node:path";
|
|
|
25
25
|
import { fileURLToPath } from "node:url";
|
|
26
26
|
import { loadWorkflowFromYaml } from "../workflow-engine/loader.js";
|
|
27
27
|
import { evaluateExpressionBatch } from "../workflow-engine/expression.js";
|
|
28
|
-
import { EncryptionPayloadCodec } from "
|
|
28
|
+
import { EncryptionPayloadCodec } from "@stigmer/temporal-codecs";
|
|
29
29
|
import type { ExecuteServerlessWorkflowInput } from "../workflows/execute-serverless-workflow.js";
|
|
30
30
|
|
|
31
31
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
@@ -12,7 +12,7 @@ import { create } from "@bufbuild/protobuf";
|
|
|
12
12
|
import { ApprovalAction, InteractionMode } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
13
13
|
import { PendingApprovalSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/approval_pb";
|
|
14
14
|
|
|
15
|
-
import { appendStructuredOutputDirective, buildPrompt, isHitlReinvocation, primarySendCarriesImages } from "../index.js";
|
|
15
|
+
import { appendStructuredOutputDirective, buildPrompt, isHitlReinvocation, primarySendCarriesImages, promptCarriesStandingContext } from "../index.js";
|
|
16
16
|
import type { BuildPromptInput } from "../index.js";
|
|
17
17
|
import { buildReinvocationPrompt, formatInteractionModePrefix, formatImplementPlanSection, formatToolApprovalProtocol, buildToolApprovalRuleFile } from "../prompt-builder.js";
|
|
18
18
|
import { PLAN_MODE_DIRECTIVE } from "../../../shared/plan-mode-prompt.js";
|
|
@@ -330,6 +330,45 @@ describe("buildPrompt", () => {
|
|
|
330
330
|
expect(prompt).toContain("APPROVED");
|
|
331
331
|
});
|
|
332
332
|
|
|
333
|
+
it("agrees with promptCarriesStandingContext on every resolution shape — the memory-selection gate can never drift from the routing (DD-008)", () => {
|
|
334
|
+
// The activity gates the (potentially embedding-backed) memory
|
|
335
|
+
// selection on this predicate; buildPrompt routes on the same one.
|
|
336
|
+
// Pin their agreement across the full reason × HITL matrix: memories
|
|
337
|
+
// reach the prompt exactly when the predicate says the prompt carries
|
|
338
|
+
// standing context.
|
|
339
|
+
const reasons: AgentResolutionReason[] = [
|
|
340
|
+
"created_first_execution",
|
|
341
|
+
"created_after_resume_failure",
|
|
342
|
+
"resumed_successfully",
|
|
343
|
+
];
|
|
344
|
+
const hitlDecisions = new Map<string, ApprovalAction>([
|
|
345
|
+
["tool-call-1", ApprovalAction.APPROVE],
|
|
346
|
+
]);
|
|
347
|
+
const hitlApprovals = [
|
|
348
|
+
create(PendingApprovalSchema, {
|
|
349
|
+
toolCallId: "tool-call-1",
|
|
350
|
+
toolName: "Write",
|
|
351
|
+
message: "Write file: gated.txt",
|
|
352
|
+
}),
|
|
353
|
+
];
|
|
354
|
+
|
|
355
|
+
for (const reason of reasons) {
|
|
356
|
+
for (const hitl of [false, true]) {
|
|
357
|
+
const prompt = buildPrompt(
|
|
358
|
+
input({
|
|
359
|
+
resolution: resolution("local", reason),
|
|
360
|
+
approvalDecisions: hitl ? hitlDecisions : undefined,
|
|
361
|
+
pendingApprovals: hitl ? hitlApprovals : [],
|
|
362
|
+
recalledMemories: { facts: ["Prefers OpenTofu."] },
|
|
363
|
+
}),
|
|
364
|
+
);
|
|
365
|
+
expect(prompt.includes("<recalled_memories>")).toBe(
|
|
366
|
+
promptCarriesStandingContext(reason),
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
|
|
333
372
|
it("uses the reinvocation prompt for a HITL reinvocation (human-meaningful, no opaque ids)", () => {
|
|
334
373
|
const approvalDecisions = new Map<string, ApprovalAction>([
|
|
335
374
|
["tool-call-1", ApprovalAction.APPROVE],
|