@stigmer/runner 3.19.1-dev.20260920100552 → 3.21.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 (70) hide show
  1. package/dist/.build-fingerprint +1 -1
  2. package/dist/__test-utils__/execution-record-fixture.d.ts +7 -0
  3. package/dist/__test-utils__/execution-record-fixture.js +10 -1
  4. package/dist/__test-utils__/execution-record-fixture.js.map +1 -1
  5. package/dist/__test-utils__/hermetic-activity.d.ts +7 -4
  6. package/dist/__test-utils__/hermetic-activity.js +12 -2
  7. package/dist/__test-utils__/hermetic-activity.js.map +1 -1
  8. package/dist/__test-utils__/turn-input-fixture.js +0 -1
  9. package/dist/__test-utils__/turn-input-fixture.js.map +1 -1
  10. package/dist/activities/execute-cursor/prompt-builder.js +8 -3
  11. package/dist/activities/execute-cursor/prompt-builder.js.map +1 -1
  12. package/dist/activities/execute-cursor/turn-settle.js +4 -1
  13. package/dist/activities/execute-cursor/turn-settle.js.map +1 -1
  14. package/dist/activities/execute-deep-agent/prompt-builder.d.ts +1 -3
  15. package/dist/activities/execute-deep-agent/prompt-builder.js +2 -3
  16. package/dist/activities/execute-deep-agent/prompt-builder.js.map +1 -1
  17. package/dist/activities/generate-session-subject.d.ts +2 -1
  18. package/dist/activities/generate-session-subject.js +18 -10
  19. package/dist/activities/generate-session-subject.js.map +1 -1
  20. package/dist/harness/run-turn.d.ts +3 -2
  21. package/dist/harness/run-turn.js +33 -6
  22. package/dist/harness/run-turn.js.map +1 -1
  23. package/dist/harness/transcript/builder.d.ts +26 -2
  24. package/dist/harness/transcript/builder.js +35 -2
  25. package/dist/harness/transcript/builder.js.map +1 -1
  26. package/dist/harness/turn-context.js +3 -1
  27. package/dist/harness/turn-context.js.map +1 -1
  28. package/dist/harness/turn-timeline.d.ts +132 -0
  29. package/dist/harness/turn-timeline.js +213 -0
  30. package/dist/harness/turn-timeline.js.map +1 -0
  31. package/dist/shared/blueprint-resolver.d.ts +14 -4
  32. package/dist/shared/blueprint-resolver.js +23 -10
  33. package/dist/shared/blueprint-resolver.js.map +1 -1
  34. package/dist/shared/builtin-assistant-prompt.d.ts +30 -0
  35. package/dist/shared/builtin-assistant-prompt.js +36 -0
  36. package/dist/shared/builtin-assistant-prompt.js.map +1 -0
  37. package/dist/shared/cold-start-timing.d.ts +18 -2
  38. package/dist/shared/cold-start-timing.js +30 -3
  39. package/dist/shared/cold-start-timing.js.map +1 -1
  40. package/package.json +5 -5
  41. package/src/__test-utils__/execution-record-fixture.ts +17 -1
  42. package/src/__test-utils__/hermetic-activity.ts +19 -6
  43. package/src/__test-utils__/timing-lines.ts +43 -0
  44. package/src/__test-utils__/turn-input-fixture.ts +0 -1
  45. package/src/activities/__tests__/generate-session-subject.test.ts +14 -0
  46. package/src/activities/execute-cursor/__tests__/goldens/prompt.enhanced.no-instructions.prompt.md +142 -0
  47. package/src/activities/execute-cursor/__tests__/hermetic/built-in-assistant.test.ts +127 -0
  48. package/src/activities/execute-cursor/__tests__/hermetic/turn-phases.test.ts +136 -0
  49. package/src/activities/execute-cursor/__tests__/prompt-goldens.test.ts +14 -1
  50. package/src/activities/execute-cursor/prompt-builder.ts +8 -3
  51. package/src/activities/execute-cursor/turn-settle.ts +4 -1
  52. package/src/activities/execute-deep-agent/__tests__/goldens/system-prompt.minimal.prompt.md +2 -1
  53. package/src/activities/execute-deep-agent/__tests__/hermetic/built-in-assistant.test.ts +101 -0
  54. package/src/activities/execute-deep-agent/__tests__/hermetic/turn-phases.test.ts +118 -0
  55. package/src/activities/execute-deep-agent/__tests__/prompt-goldens.test.ts +1 -1
  56. package/src/activities/execute-deep-agent/prompt-builder.ts +3 -5
  57. package/src/activities/generate-session-subject.ts +20 -13
  58. package/src/harness/README.md +4 -1
  59. package/src/harness/__tests__/run-turn.test.ts +53 -0
  60. package/src/harness/__tests__/turn-timeline.test.ts +274 -0
  61. package/src/harness/run-turn.ts +36 -6
  62. package/src/harness/transcript/__tests__/builder.test.ts +69 -1
  63. package/src/harness/transcript/builder.ts +39 -2
  64. package/src/harness/turn-context.ts +3 -1
  65. package/src/harness/turn-timeline.ts +248 -0
  66. package/src/shared/__tests__/blueprint-resolver.test.ts +78 -8
  67. package/src/shared/__tests__/cold-start-timing.test.ts +53 -5
  68. package/src/shared/blueprint-resolver.ts +25 -12
  69. package/src/shared/builtin-assistant-prompt.ts +38 -0
  70. package/src/shared/cold-start-timing.ts +29 -3
@@ -0,0 +1,213 @@
1
+ /**
2
+ * The turn runtime's timeline of one engine turn, folded from the transcript
3
+ * events every harness already emits, and written once at settle as the
4
+ * `turn_phases` `stigmer_timing` line.
5
+ *
6
+ * What it answers, for every harness alike and for any harness added later
7
+ * without a line in an adapter: when the user first saw something happen,
8
+ * how many model rounds and tool calls the turn took, where the sub-agents
9
+ * ran, and where the turn's longest silence was. It is the per-turn,
10
+ * CLIENT-PERCEIVED measurement from the runner's vantage, from the turn's
11
+ * origin (the activity's start, the same origin `execution_setup` counts
12
+ * from, so the two lines subtract without a join) to the adapter's return;
13
+ * the completion epilogue and the terminal persist that follow are the
14
+ * client's own end-to-end, read at `subscribe`. Its counterpart is the cloud
15
+ * proxy's `ProxyTiming` (`agentexecution/v1/usage.proto`): per model CALL,
16
+ * server-side, what the provider did. Neither restates the other; a report
17
+ * that wants both joins them by `execution_id`.
18
+ *
19
+ * Why a fold over the transcript events and not a mark in each adapter: the
20
+ * transcript builder (`transcript/builder.ts`) is the one view the runtime
21
+ * has of every harness's turn — model rounds, text, tools, sub-agents all
22
+ * reach it as a translator's output on one union — so a fold over it is
23
+ * written once and holds for the Cursor adapter, the native adapter and the
24
+ * next one. `UsageAccumulator` (`usage-accumulator.ts`) is the same shape
25
+ * for the usage deltas; this is that shape for the events.
26
+ *
27
+ * The fold's rules, each with an arm in `__tests__/turn-timeline.test.ts`:
28
+ *
29
+ * - Three instants, ROOT scope only (a sub-agent's text is not what the
30
+ * user is watching): `first_event_ms`, the first event of any kind;
31
+ * `first_visible_token_ms`, the first `text_delta` or `reasoning_delta`
32
+ * (both stream into the console as tokens); `first_text_ms`, the first
33
+ * `text_delta`. The two token instants are the cross-harness axes: with
34
+ * extended thinking on, the visible instant moves earlier and the text
35
+ * instant later, and a comparison needs both. `first_event_ms` is
36
+ * harness-relative — on native the first event is `message_start`, the
37
+ * model stream opening; on Cursor it is whatever the SDK delivered first —
38
+ * and is kept as a forensic (engine-ready to first model event), never as
39
+ * an axis. An instant that never happened is `null`.
40
+ * - One `model_round` span per `runId`, `message_start` to `message_finish`.
41
+ * What a `runId` is belongs to the translator: LangGraph's LLM-call run on
42
+ * native, one model round; a minted segment `<run>:<n>` on Cursor, a
43
+ * stretch of assistant output between tool calls, which the SDK does not
44
+ * let us tell apart from a provider round. The line's `rounds` reads the
45
+ * same way.
46
+ * - One `tool:<name>` span per `callId` (`tool:<slug>/<name>` for an MCP
47
+ * tool, so the MCP phase the runner skill's law asks for is legible),
48
+ * `tool_started` to the FIRST `tool_finished` or `tool_error`; a later
49
+ * fact for a settled span changes nothing, the builder's own upsert rule
50
+ * (Cursor completes every call twice). `approval_proposed` opens nothing:
51
+ * a call the engine held before it ran is not a tool phase.
52
+ * - One `sub_agent:<name>` span per `subAgentId`, opened by
53
+ * `sub_agent_started`, closed by `finished` or `failed`.
54
+ * - A fact that carries `observedAt` is placed at that instant, everything
55
+ * else at the fold's clock — the builder's rule for `completedAt`
56
+ * (`transcript/events.ts`, `Observed`), restated here because the
57
+ * alternative repeats the error #1097 fixed, for tool phases and on Cursor
58
+ * alone: a completion the SDK's delta channel reported is folded one
59
+ * stream event later, seconds while the model narrates, and a comparison
60
+ * that read the fold's clock would charge those seconds to Cursor's tools.
61
+ * Placing an observed instant needs a wall-clock origin beside the
62
+ * `performance.now()` one; the runtime captures both together.
63
+ * - `max_gap_ms`, the longest wait between two consecutive events, whatever
64
+ * their kind: the turn's longest silence as the user experienced it.
65
+ * `null` under two events.
66
+ * - A span still open at settle closes at settle: an interrupted turn's
67
+ * spans end where the turn did.
68
+ *
69
+ * The line: `emitTimingLog("turn_phases", context, recorder)` over a
70
+ * `TimingRecorder` on the turn's origin, every span appended in start order
71
+ * through `span()`. This is the first `stigmer_timing` event whose segments
72
+ * OVERLAP (a tool inside a round, a sub-agent across rounds); the recorder's
73
+ * `total_ms` is the latest end, not a sum, and a reader that summed the
74
+ * other timelines' segments must not sum this one's. No histogram mirrors it
75
+ * yet: the benchmark report is its reader and reads the log; an aggregate
76
+ * earns its instrument when a dashboard asks.
77
+ *
78
+ * Failure posture, the timing module's: the fold is arithmetic over the
79
+ * event and cannot affect a turn; `emit` is best-effort through
80
+ * `emitTimingLog`. Nothing here is persisted, and nothing branches on it.
81
+ */
82
+ import { TimingRecorder, emitTimingLog } from "../shared/cold-start-timing.js";
83
+ /** The `stigmer_timing` selector of the line this module emits. */
84
+ export const TURN_PHASES_EVENT = "turn_phases";
85
+ export class TurnTimeline {
86
+ clock;
87
+ firstEventMs;
88
+ firstVisibleTokenMs;
89
+ firstTextMs;
90
+ lastEventMs;
91
+ maxGapMs;
92
+ rounds = new Map();
93
+ tools = new Map();
94
+ subAgents = new Map();
95
+ constructor(clock) {
96
+ this.clock = clock;
97
+ }
98
+ /** The builder's observer: place one folded event on the timeline. */
99
+ observe(event) {
100
+ const at = this.clock.now();
101
+ this.noteEvent(at);
102
+ // Root scope only: a sub-agent's tokens stream into its own row, not the
103
+ // thread the user is watching.
104
+ if ((event.kind === "text_delta" || event.kind === "reasoning_delta") && event.subAgentId === undefined) {
105
+ this.firstVisibleTokenMs ??= at;
106
+ if (event.kind === "text_delta")
107
+ this.firstTextMs ??= at;
108
+ }
109
+ switch (event.kind) {
110
+ case "message_start":
111
+ this.open(this.rounds, event.runId, "model_round", at);
112
+ return;
113
+ case "message_finish":
114
+ this.close(this.rounds, event.runId, at);
115
+ return;
116
+ case "tool_started":
117
+ this.open(this.tools, event.callId, toolSpanName(event.name, event.mcpServerSlug), at);
118
+ return;
119
+ case "tool_finished":
120
+ case "tool_error":
121
+ this.close(this.tools, event.callId, this.placeObserved(event.observedAt, at));
122
+ return;
123
+ case "sub_agent_started":
124
+ this.open(this.subAgents, event.subAgentId, `sub_agent:${event.name}`, at);
125
+ return;
126
+ case "sub_agent_finished":
127
+ case "sub_agent_failed":
128
+ this.close(this.subAgents, event.subAgentId, at);
129
+ return;
130
+ case "text_delta":
131
+ case "reasoning_delta":
132
+ case "tool_arg_delta":
133
+ case "tool_output_delta":
134
+ case "approval_proposed":
135
+ case "system_note":
136
+ return;
137
+ default: {
138
+ const exhaustive = event;
139
+ throw new Error(`unknown transcript event ${String(exhaustive.kind)}`);
140
+ }
141
+ }
142
+ }
143
+ /**
144
+ * Write the line, once, at settle. Spans still open close now; the
145
+ * runtime's context (`execution_id`, `session_id`, `turn_seq`, `harness`,
146
+ * `outcome`) rides beside the fold's facts.
147
+ */
148
+ emit(context) {
149
+ const settledAt = this.clock.now();
150
+ const recorder = new TimingRecorder(this.clock.originMs);
151
+ const spans = [...this.rounds.values(), ...this.tools.values(), ...this.subAgents.values()]
152
+ .sort((a, b) => a.startMs - b.startMs);
153
+ for (const span of spans) {
154
+ recorder.span(span.name, span.startMs, span.endMs ?? settledAt);
155
+ }
156
+ emitTimingLog(TURN_PHASES_EVENT, {
157
+ ...context,
158
+ first_event_ms: this.offset(this.firstEventMs),
159
+ first_visible_token_ms: this.offset(this.firstVisibleTokenMs),
160
+ first_text_ms: this.offset(this.firstTextMs),
161
+ rounds: this.rounds.size,
162
+ tool_calls: this.tools.size,
163
+ sub_agents: this.subAgents.size,
164
+ max_gap_ms: this.maxGapMs === undefined ? null : round1(this.maxGapMs),
165
+ }, recorder);
166
+ }
167
+ noteEvent(at) {
168
+ this.firstEventMs ??= at;
169
+ if (this.lastEventMs !== undefined) {
170
+ const gap = at - this.lastEventMs;
171
+ if (this.maxGapMs === undefined || gap > this.maxGapMs)
172
+ this.maxGapMs = gap;
173
+ }
174
+ this.lastEventMs = at;
175
+ }
176
+ /** A span per identity: a re-emitted start (a resumed seeded call) keeps the first start. */
177
+ open(spans, id, name, at) {
178
+ if (spans.has(id))
179
+ return;
180
+ spans.set(id, { name, startMs: at, endMs: undefined });
181
+ }
182
+ /** The FIRST close settles a span; a later fact for it changes nothing. A close for an unknown id is ignored. */
183
+ close(spans, id, at) {
184
+ const span = spans.get(id);
185
+ if (!span || span.endMs !== undefined)
186
+ return;
187
+ span.endMs = at;
188
+ }
189
+ /**
190
+ * Where a fact goes on the `performance.now()` scale: its observed instant
191
+ * translated through the paired origins when it carries one, else the fold's
192
+ * clock. An unparseable stamp falls back to the fold's clock rather than
193
+ * losing the fact.
194
+ */
195
+ placeObserved(observedAt, foldAt) {
196
+ if (observedAt === undefined)
197
+ return foldAt;
198
+ const wallMs = Date.parse(observedAt);
199
+ if (Number.isNaN(wallMs))
200
+ return foldAt;
201
+ return this.clock.originMs + (wallMs - this.clock.originWallMs);
202
+ }
203
+ offset(absoluteMs) {
204
+ return absoluteMs === undefined ? null : round1(absoluteMs - this.clock.originMs);
205
+ }
206
+ }
207
+ function toolSpanName(name, mcpServerSlug) {
208
+ return mcpServerSlug ? `tool:${mcpServerSlug}/${name}` : `tool:${name}`;
209
+ }
210
+ function round1(ms) {
211
+ return Math.round(ms * 10) / 10;
212
+ }
213
+ //# sourceMappingURL=turn-timeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"turn-timeline.js","sourceRoot":"","sources":["../../src/harness/turn-timeline.ts"],"names":[],"mappings":"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"}
@@ -6,13 +6,21 @@
6
6
  * mcp_server_usages. Also merges agent-level and session-level MCP usages
7
7
  * and skill refs following the same merge semantics.
8
8
  *
9
+ * A session with an EMPTY agent_instance_id is the built-in assistant
10
+ * (session/v1/spec.proto): the chain stops at the session, `agent` is
11
+ * undefined, the instructions are empty (each harness's prompt builder
12
+ * substitutes the one built-in prompt, shared/builtin-assistant-prompt.ts),
13
+ * there are no sub-agents, and the session's own MCP usages and skill refs
14
+ * are the whole tool set — the same merge with an empty agent side, so no
15
+ * consumer downstream needs an agent-less arm of its own.
16
+ *
9
17
  * Workspace isolation: resolved workspace directories are validated to
10
18
  * ensure they never point at the runner's own app directory. Paths
11
19
  * containing runner-internal markers are rejected with a warning.
12
20
  */
13
21
  import type { StigmerClient } from "../client/stigmer-client.js";
14
22
  import type { Agent } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
15
- import type { AgentSpec, McpServerUsage, SubAgent } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/spec_pb";
23
+ import type { McpServerUsage, SubAgent } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/spec_pb";
16
24
  import type { Session } from "@stigmer/protos/ai/stigmer/agentic/session/v1/api_pb";
17
25
  import type { SessionSpec } from "@stigmer/protos/ai/stigmer/agentic/session/v1/spec_pb";
18
26
  import type { WorkspaceEntry } from "@stigmer/protos/ai/stigmer/agentic/session/v1/workspace_pb";
@@ -23,8 +31,8 @@ export interface CloudRepo {
23
31
  startingRef?: string;
24
32
  }
25
33
  export interface ResolvedBlueprint {
26
- agent: Agent;
27
- agentSpec: AgentSpec;
34
+ /** The agent the session is bound to; undefined for the built-in assistant. */
35
+ agent: Agent | undefined;
28
36
  session: Session;
29
37
  sessionSpec: SessionSpec;
30
38
  instructions: string;
@@ -37,7 +45,9 @@ export interface ResolvedBlueprint {
37
45
  * Resolve the full agent blueprint from the execution chain.
38
46
  *
39
47
  * Chain: execution.spec.sessionId -> session.spec.agentInstanceId ->
40
- * agentInstance.spec.agentId -> agent (with full spec)
48
+ * agentInstance.spec.agentId -> agent (with full spec); an empty
49
+ * agent_instance_id ends the chain at the session (the built-in
50
+ * assistant).
41
51
  */
42
52
  export declare function resolveBlueprint(client: StigmerClient, session: Session): Promise<ResolvedBlueprint>;
43
53
  /**
@@ -6,6 +6,14 @@
6
6
  * mcp_server_usages. Also merges agent-level and session-level MCP usages
7
7
  * and skill refs following the same merge semantics.
8
8
  *
9
+ * A session with an EMPTY agent_instance_id is the built-in assistant
10
+ * (session/v1/spec.proto): the chain stops at the session, `agent` is
11
+ * undefined, the instructions are empty (each harness's prompt builder
12
+ * substitutes the one built-in prompt, shared/builtin-assistant-prompt.ts),
13
+ * there are no sub-agents, and the session's own MCP usages and skill refs
14
+ * are the whole tool set — the same merge with an empty agent side, so no
15
+ * consumer downstream needs an agent-less arm of its own.
16
+ *
9
17
  * Workspace isolation: resolved workspace directories are validated to
10
18
  * ensure they never point at the runner's own app directory. Paths
11
19
  * containing runner-internal markers are rejected with a warning.
@@ -20,24 +28,29 @@ export { mergeMcpServerUsages } from "./mcp-resolver.js";
20
28
  * Resolve the full agent blueprint from the execution chain.
21
29
  *
22
30
  * Chain: execution.spec.sessionId -> session.spec.agentInstanceId ->
23
- * agentInstance.spec.agentId -> agent (with full spec)
31
+ * agentInstance.spec.agentId -> agent (with full spec); an empty
32
+ * agent_instance_id ends the chain at the session (the built-in
33
+ * assistant).
24
34
  */
25
35
  export async function resolveBlueprint(client, session) {
26
36
  const sessionSpec = session.spec;
27
- const agentInstance = await client.getAgentInstance(sessionSpec.agentInstanceId);
28
- const agentId = agentInstance.spec.agentId;
29
- const agent = await client.getAgent(agentId);
30
- const agentSpec = agent.spec;
31
- const mergedMcpServerUsages = mergeMcpServerUsages(agentSpec.mcpServerUsages, sessionSpec.mcpServerUsages);
32
- const mergedSkillRefs = mergeSkillRefs(agentSpec.skillRefs, sessionSpec.skillRefs);
37
+ let agent;
38
+ let agentSpec;
39
+ if (sessionSpec.agentInstanceId !== "") {
40
+ const agentInstance = await client.getAgentInstance(sessionSpec.agentInstanceId);
41
+ const agentId = agentInstance.spec.agentId;
42
+ agent = await client.getAgent(agentId);
43
+ agentSpec = agent.spec;
44
+ }
45
+ const mergedMcpServerUsages = mergeMcpServerUsages(agentSpec?.mcpServerUsages ?? [], sessionSpec.mcpServerUsages);
46
+ const mergedSkillRefs = mergeSkillRefs(agentSpec?.skillRefs ?? [], sessionSpec.skillRefs);
33
47
  const cloudRepos = resolveCloudRepos(sessionSpec.workspaceEntries);
34
48
  return {
35
49
  agent,
36
- agentSpec,
37
50
  session,
38
51
  sessionSpec,
39
- instructions: agentSpec.instructions,
40
- subAgents: agentSpec.subAgents,
52
+ instructions: agentSpec?.instructions ?? "",
53
+ subAgents: agentSpec?.subAgents ?? [],
41
54
  mergedMcpServerUsages,
42
55
  mergedSkillRefs,
43
56
  cloudRepos,
@@ -1 +1 @@
1
- {"version":3,"file":"blueprint-resolver.js","sourceRoot":"","sources":["../../src/shared/blueprint-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AASH,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAEzD,6EAA6E;AAC7E,2EAA2E;AAC3E,6EAA6E;AAC7E,iCAAiC;AACjC,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAmBzD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAAqB,EACrB,OAAgB;IAEhB,MAAM,WAAW,GAAG,OAAO,CAAC,IAAK,CAAC;IAElC,MAAM,aAAa,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC;IACjF,MAAM,OAAO,GAAG,aAAa,CAAC,IAAK,CAAC,OAAO,CAAC;IAC5C,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC7C,MAAM,SAAS,GAAG,KAAK,CAAC,IAAK,CAAC;IAE9B,MAAM,qBAAqB,GAAG,oBAAoB,CAChD,SAAS,CAAC,eAAe,EACzB,WAAW,CAAC,eAAe,CAC5B,CAAC;IAEF,MAAM,eAAe,GAAG,cAAc,CACpC,SAAS,CAAC,SAAS,EACnB,WAAW,CAAC,SAAS,CACtB,CAAC;IAEF,MAAM,UAAU,GAAG,iBAAiB,CAAC,WAAW,CAAC,gBAAgB,CAAC,CAAC;IAEnE,OAAO;QACL,KAAK;QACL,SAAS;QACT,OAAO;QACP,WAAW;QACX,YAAY,EAAE,SAAS,CAAC,YAAY;QACpC,SAAS,EAAE,SAAS,CAAC,SAAS;QAC9B,qBAAqB;QACrB,eAAe;QACf,UAAU;KACX,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,wBAAwB;AACxB,8EAA8E;AAE9E;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,gBAAkC;IAClE,MAAM,KAAK,GAAgB,EAAE,CAAC;IAE9B,KAAK,MAAM,KAAK,IAAI,gBAAgB,EAAE,CAAC;QACrC,IAAI,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC5C,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC;YACtC,KAAK,CAAC,IAAI,CAAC;gBACT,GAAG,EAAE,GAAG,CAAC,GAAG;gBACZ,WAAW,EAAE,GAAG,CAAC,MAAM,IAAI,SAAS;aACrC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,8EAA8E;AAC9E,wBAAwB;AACxB,8EAA8E;AAE9E;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAC5B,SAAiC,EACjC,WAAmC;IAEnC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAgC,CAAC;IAEvD,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;QAC5B,IAAI,GAAG,CAAC,IAAI;YAAE,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC1C,CAAC;IAED,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;QAC9B,IAAI,GAAG,CAAC,IAAI;YAAE,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC1C,CAAC;IAED,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;AAC9B,CAAC"}
1
+ {"version":3,"file":"blueprint-resolver.js","sourceRoot":"","sources":["../../src/shared/blueprint-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AASH,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAEzD,6EAA6E;AAC7E,2EAA2E;AAC3E,6EAA6E;AAC7E,iCAAiC;AACjC,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAmBzD;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAAqB,EACrB,OAAgB;IAEhB,MAAM,WAAW,GAAG,OAAO,CAAC,IAAK,CAAC;IAElC,IAAI,KAAwB,CAAC;IAC7B,IAAI,SAAgC,CAAC;IACrC,IAAI,WAAW,CAAC,eAAe,KAAK,EAAE,EAAE,CAAC;QACvC,MAAM,aAAa,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC;QACjF,MAAM,OAAO,GAAG,aAAa,CAAC,IAAK,CAAC,OAAO,CAAC;QAC5C,KAAK,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACvC,SAAS,GAAG,KAAK,CAAC,IAAK,CAAC;IAC1B,CAAC;IAED,MAAM,qBAAqB,GAAG,oBAAoB,CAChD,SAAS,EAAE,eAAe,IAAI,EAAE,EAChC,WAAW,CAAC,eAAe,CAC5B,CAAC;IAEF,MAAM,eAAe,GAAG,cAAc,CACpC,SAAS,EAAE,SAAS,IAAI,EAAE,EAC1B,WAAW,CAAC,SAAS,CACtB,CAAC;IAEF,MAAM,UAAU,GAAG,iBAAiB,CAAC,WAAW,CAAC,gBAAgB,CAAC,CAAC;IAEnE,OAAO;QACL,KAAK;QACL,OAAO;QACP,WAAW;QACX,YAAY,EAAE,SAAS,EAAE,YAAY,IAAI,EAAE;QAC3C,SAAS,EAAE,SAAS,EAAE,SAAS,IAAI,EAAE;QACrC,qBAAqB;QACrB,eAAe;QACf,UAAU;KACX,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,wBAAwB;AACxB,8EAA8E;AAE9E;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,gBAAkC;IAClE,MAAM,KAAK,GAAgB,EAAE,CAAC;IAE9B,KAAK,MAAM,KAAK,IAAI,gBAAgB,EAAE,CAAC;QACrC,IAAI,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC5C,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC;YACtC,KAAK,CAAC,IAAI,CAAC;gBACT,GAAG,EAAE,GAAG,CAAC,GAAG;gBACZ,WAAW,EAAE,GAAG,CAAC,MAAM,IAAI,SAAS;aACrC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,8EAA8E;AAC9E,wBAAwB;AACxB,8EAA8E;AAE9E;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAC5B,SAAiC,EACjC,WAAmC;IAEnC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAgC,CAAC;IAEvD,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;QAC5B,IAAI,GAAG,CAAC,IAAI;YAAE,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC1C,CAAC;IAED,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;QAC9B,IAAI,GAAG,CAAC,IAAI;YAAE,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC1C,CAAC;IAED,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * The built-in assistant's instructions: the ONE text a run reads when its
3
+ * blueprint carries no instructions — because the session names no agent
4
+ * (session/v1/spec.proto, an empty agent_instance_id) or because the agent
5
+ * it names left its instructions empty. Both harnesses' prompt builders
6
+ * substitute these words on that arm and frame them their own way (the
7
+ * `prompt-sections.ts` doctrine: the framing is house style, the words are
8
+ * shared), so a person who picks no agent meets the same assistant on the
9
+ * native and the Cursor harness, and a maintainer changes the assistant in
10
+ * one place.
11
+ *
12
+ * A prompt is code: versioned here, pinned by the prompt goldens of both
13
+ * harnesses (`execute-deep-agent/__tests__/goldens/system-prompt.minimal.prompt.md`,
14
+ * `execute-cursor/__tests__/goldens/*no-instructions*`). There is no stored
15
+ * "default agent" row anywhere whose instructions could drift from these.
16
+ *
17
+ * What the words leave to the builders on purpose: the response rules, the
18
+ * sub-agent rules, the skills protocol and every other section quote an
19
+ * engine's tools and stay per harness. These words say who the assistant
20
+ * is and how it works with a person; nothing here names a tool.
21
+ */
22
+ /** The display name every surface uses for the built-in assistant. */
23
+ export declare const BUILT_IN_ASSISTANT_NAME = "Assistant";
24
+ export declare const BUILT_IN_ASSISTANT_INSTRUCTIONS: string;
25
+ /**
26
+ * The instructions a run reads: the blueprint's own when it has any, the
27
+ * built-in assistant's otherwise. Both prompt builders call this on their
28
+ * instructions arm so neither carries a second copy of the fallback.
29
+ */
30
+ export declare function effectiveInstructions(instructions: string): string;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * The built-in assistant's instructions: the ONE text a run reads when its
3
+ * blueprint carries no instructions — because the session names no agent
4
+ * (session/v1/spec.proto, an empty agent_instance_id) or because the agent
5
+ * it names left its instructions empty. Both harnesses' prompt builders
6
+ * substitute these words on that arm and frame them their own way (the
7
+ * `prompt-sections.ts` doctrine: the framing is house style, the words are
8
+ * shared), so a person who picks no agent meets the same assistant on the
9
+ * native and the Cursor harness, and a maintainer changes the assistant in
10
+ * one place.
11
+ *
12
+ * A prompt is code: versioned here, pinned by the prompt goldens of both
13
+ * harnesses (`execute-deep-agent/__tests__/goldens/system-prompt.minimal.prompt.md`,
14
+ * `execute-cursor/__tests__/goldens/*no-instructions*`). There is no stored
15
+ * "default agent" row anywhere whose instructions could drift from these.
16
+ *
17
+ * What the words leave to the builders on purpose: the response rules, the
18
+ * sub-agent rules, the skills protocol and every other section quote an
19
+ * engine's tools and stay per harness. These words say who the assistant
20
+ * is and how it works with a person; nothing here names a tool.
21
+ */
22
+ /** The display name every surface uses for the built-in assistant. */
23
+ export const BUILT_IN_ASSISTANT_NAME = "Assistant";
24
+ export const BUILT_IN_ASSISTANT_INSTRUCTIONS = [
25
+ "You are Stigmer's assistant. Help with whatever the person brings: answer, reason, write and edit, and use the tools and skills attached to this conversation when they help.",
26
+ "Be direct and concrete. Say what you do not know. Ask when a request is ambiguous. Prefer changing what exists over creating anew.",
27
+ ].join("\n");
28
+ /**
29
+ * The instructions a run reads: the blueprint's own when it has any, the
30
+ * built-in assistant's otherwise. Both prompt builders call this on their
31
+ * instructions arm so neither carries a second copy of the fallback.
32
+ */
33
+ export function effectiveInstructions(instructions) {
34
+ return instructions === "" ? BUILT_IN_ASSISTANT_INSTRUCTIONS : instructions;
35
+ }
36
+ //# sourceMappingURL=builtin-assistant-prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builtin-assistant-prompt.js","sourceRoot":"","sources":["../../src/shared/builtin-assistant-prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,sEAAsE;AACtE,MAAM,CAAC,MAAM,uBAAuB,GAAG,WAAW,CAAC;AAEnD,MAAM,CAAC,MAAM,+BAA+B,GAAG;IAC7C,+KAA+K;IAC/K,oIAAoI;CACrI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,YAAoB;IACxD,OAAO,YAAY,KAAK,EAAE,CAAC,CAAC,CAAC,+BAA+B,CAAC,CAAC,CAAC,YAAY,CAAC;AAC9E,CAAC"}
@@ -24,7 +24,7 @@ export interface TimingSegment {
24
24
  readonly durationMs: number;
25
25
  }
26
26
  /**
27
- * Records a linear sequence of named segments.
27
+ * Records named segments on one timeline, two ways.
28
28
  *
29
29
  * `mark(name)` closes the span from the previous mark (or the origin) and
30
30
  * names it — so instrumentation reads as one line placed AFTER the work it
@@ -35,11 +35,22 @@ export interface TimingSegment {
35
35
  * const execution = await client.getExecution(executionId);
36
36
  * timing.mark("fetch_execution");
37
37
  * ```
38
+ *
39
+ * `span(name, startMs, endMs)` records a segment with explicit bounds, for a
40
+ * timeline whose phases OVERLAP (a tool call inside a model round, a
41
+ * sub-agent across two rounds) and so cannot be written as a chain of marks.
42
+ * A span never moves the mark cursor: a `mark` after a `span` still measures
43
+ * from the previous MARK, so the two idioms compose on one recorder without
44
+ * either changing what the other means. `totalMs()` is the latest end on the
45
+ * timeline, whichever way it was recorded — for a mark-only recorder that is
46
+ * the last mark, as it always was.
38
47
  */
39
48
  export declare class TimingRecorder {
40
49
  private readonly originMs;
41
50
  private readonly segments;
42
51
  private lastMarkMs;
52
+ /** Absolute end of the segment that ends latest, by either idiom. */
53
+ private latestEndMs;
43
54
  /**
44
55
  * @param originMs absolute `performance.now()`-scale origin. Defaults to
45
56
  * "now" (per-execution timelines). Pass 0 for a process-lifetime timeline
@@ -49,7 +60,12 @@ export declare class TimingRecorder {
49
60
  constructor(originMs?: number);
50
61
  /** Close the span since the previous mark (or origin) and name it. */
51
62
  mark(name: string): void;
52
- /** Total elapsed time from the origin to the latest mark (ms). */
63
+ /**
64
+ * Record a segment with explicit absolute bounds (`performance.now()`
65
+ * scale, like the origin). Leaves the mark cursor where it was.
66
+ */
67
+ span(name: string, startMs: number, endMs: number): void;
68
+ /** Elapsed time from the origin to the latest end on the timeline (ms). */
53
69
  totalMs(): number;
54
70
  snapshot(): readonly TimingSegment[];
55
71
  }
@@ -21,7 +21,7 @@
21
21
  // while per-call dynamic imports raced under concurrent emissions.
22
22
  import { getInstruments } from "../otel-metrics.js";
23
23
  /**
24
- * Records a linear sequence of named segments.
24
+ * Records named segments on one timeline, two ways.
25
25
  *
26
26
  * `mark(name)` closes the span from the previous mark (or the origin) and
27
27
  * names it — so instrumentation reads as one line placed AFTER the work it
@@ -32,11 +32,22 @@ import { getInstruments } from "../otel-metrics.js";
32
32
  * const execution = await client.getExecution(executionId);
33
33
  * timing.mark("fetch_execution");
34
34
  * ```
35
+ *
36
+ * `span(name, startMs, endMs)` records a segment with explicit bounds, for a
37
+ * timeline whose phases OVERLAP (a tool call inside a model round, a
38
+ * sub-agent across two rounds) and so cannot be written as a chain of marks.
39
+ * A span never moves the mark cursor: a `mark` after a `span` still measures
40
+ * from the previous MARK, so the two idioms compose on one recorder without
41
+ * either changing what the other means. `totalMs()` is the latest end on the
42
+ * timeline, whichever way it was recorded — for a mark-only recorder that is
43
+ * the last mark, as it always was.
35
44
  */
36
45
  export class TimingRecorder {
37
46
  originMs;
38
47
  segments = [];
39
48
  lastMarkMs;
49
+ /** Absolute end of the segment that ends latest, by either idiom. */
50
+ latestEndMs;
40
51
  /**
41
52
  * @param originMs absolute `performance.now()`-scale origin. Defaults to
42
53
  * "now" (per-execution timelines). Pass 0 for a process-lifetime timeline
@@ -46,6 +57,7 @@ export class TimingRecorder {
46
57
  constructor(originMs = performance.now()) {
47
58
  this.originMs = originMs;
48
59
  this.lastMarkMs = originMs;
60
+ this.latestEndMs = originMs;
49
61
  }
50
62
  /** Close the span since the previous mark (or origin) and name it. */
51
63
  mark(name) {
@@ -56,10 +68,25 @@ export class TimingRecorder {
56
68
  durationMs: round1(now - this.lastMarkMs),
57
69
  });
58
70
  this.lastMarkMs = now;
71
+ if (now > this.latestEndMs)
72
+ this.latestEndMs = now;
73
+ }
74
+ /**
75
+ * Record a segment with explicit absolute bounds (`performance.now()`
76
+ * scale, like the origin). Leaves the mark cursor where it was.
77
+ */
78
+ span(name, startMs, endMs) {
79
+ this.segments.push({
80
+ name,
81
+ startMs: round1(startMs - this.originMs),
82
+ durationMs: round1(endMs - startMs),
83
+ });
84
+ if (endMs > this.latestEndMs)
85
+ this.latestEndMs = endMs;
59
86
  }
60
- /** Total elapsed time from the origin to the latest mark (ms). */
87
+ /** Elapsed time from the origin to the latest end on the timeline (ms). */
61
88
  totalMs() {
62
- return round1(this.lastMarkMs - this.originMs);
89
+ return round1(this.latestEndMs - this.originMs);
63
90
  }
64
91
  snapshot() {
65
92
  return this.segments;
@@ -1 +1 @@
1
- {"version":3,"file":"cold-start-timing.js","sourceRoot":"","sources":["../../src/shared/cold-start-timing.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cold-start-timing.js","sourceRoot":"","sources":["../../src/shared/cold-start-timing.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.19.1-dev.20260920100552",
3
+ "version": "3.21.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",
@@ -104,10 +104,10 @@
104
104
  "@opentelemetry/sdk-metrics": "^2.0.0",
105
105
  "@opentelemetry/sdk-trace-base": "^2.0.0",
106
106
  "@opentelemetry/sdk-trace-node": "^2.0.0",
107
- "@stigmer/outbound": "3.19.1-dev.20260920100552",
108
- "@stigmer/protos": "3.19.1-dev.20260920100552",
109
- "@stigmer/temporal-codecs": "3.19.1-dev.20260920100552",
110
- "@stigmer/zip-structure": "3.19.1-dev.20260920100552",
107
+ "@stigmer/outbound": "3.21.0",
108
+ "@stigmer/protos": "3.21.0",
109
+ "@stigmer/temporal-codecs": "3.21.0",
110
+ "@stigmer/zip-structure": "3.21.0",
111
111
  "@temporalio/activity": "1.16.2",
112
112
  "@temporalio/common": "1.16.2",
113
113
  "@temporalio/interceptors-opentelemetry": "1.16.2",
@@ -75,6 +75,13 @@ export interface ExecutionRecordOptions {
75
75
  readonly structuredOutputSchema?: JsonObject;
76
76
  /** The agent's declared sub-agents (`AgentSpec.sub_agents`). */
77
77
  readonly subAgents?: SubAgent[];
78
+ /**
79
+ * The built-in assistant: the session names NO agent instance, so the
80
+ * record carries no instance and no agent and the activity must run on
81
+ * the one built-in prompt with the session's own tools. `instructions`
82
+ * and `subAgents` are ignored (there is no agent to declare them).
83
+ */
84
+ readonly builtInAssistant?: boolean;
78
85
  /** The control plane's STOP lever; see `ExecutionRecordInput.controlSignal`. */
79
86
  readonly controlSignal?: ExecutionRecordInput["controlSignal"];
80
87
  readonly ids?: ExecutionRecordIds;
@@ -100,10 +107,19 @@ export function executionRecordFixture(options: ExecutionRecordOptions): Executi
100
107
  const session: Session = create(SessionSchema, {
101
108
  metadata: create(ApiResourceMetadataSchema, { id: ids.sessionId, org: ids.org, name: ids.sessionId }),
102
109
  spec: create(SessionSpecSchema, {
103
- agentInstanceId: ids.agentInstanceId,
110
+ agentInstanceId: options.builtInAssistant === true ? "" : ids.agentInstanceId,
104
111
  workspaceEntries: options.workspaceEntries ?? [],
105
112
  }),
106
113
  });
114
+ if (options.builtInAssistant === true) {
115
+ return new ExecutionRecord({
116
+ execution,
117
+ session,
118
+ agentInstance: undefined,
119
+ agent: undefined,
120
+ controlSignal: options.controlSignal,
121
+ });
122
+ }
107
123
  const agentInstance: AgentInstance = create(AgentInstanceSchema, {
108
124
  metadata: create(ApiResourceMetadataSchema, { id: ids.agentInstanceId, org: ids.org, name: ids.agentInstanceId }),
109
125
  spec: create(AgentInstanceSpecSchema, { agentId: ids.agentId }),