@exaudeus/workrail 3.75.0 → 3.77.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/console-ui/assets/index-D9pYbwS0.js +28 -0
- package/dist/console-ui/index.html +1 -1
- package/dist/coordinators/adaptive-pipeline.d.ts +8 -0
- package/dist/coordinators/context-assembly.d.ts +4 -0
- package/dist/coordinators/context-assembly.js +156 -0
- package/dist/coordinators/modes/full-pipeline.d.ts +1 -1
- package/dist/coordinators/modes/full-pipeline.js +140 -27
- package/dist/coordinators/modes/implement-shared.d.ts +3 -2
- package/dist/coordinators/modes/implement-shared.js +16 -6
- package/dist/coordinators/modes/implement.js +49 -3
- package/dist/coordinators/pipeline-run-context.d.ts +1811 -0
- package/dist/coordinators/pipeline-run-context.js +114 -0
- package/dist/daemon/context-loader.d.ts +1 -1
- package/dist/daemon/core/agent-client.d.ts +7 -0
- package/dist/daemon/core/agent-client.js +31 -0
- package/dist/daemon/core/index.d.ts +6 -0
- package/dist/daemon/core/index.js +19 -0
- package/dist/daemon/core/session-context.d.ts +14 -0
- package/dist/daemon/core/session-context.js +24 -0
- package/dist/daemon/core/session-result.d.ts +10 -0
- package/dist/daemon/core/session-result.js +92 -0
- package/dist/daemon/core/system-prompt.d.ts +6 -0
- package/dist/daemon/core/system-prompt.js +151 -0
- package/dist/daemon/io/conversation-log.d.ts +2 -0
- package/dist/daemon/io/conversation-log.js +45 -0
- package/dist/daemon/io/execution-stats.d.ts +7 -0
- package/dist/daemon/io/execution-stats.js +86 -0
- package/dist/daemon/io/index.d.ts +5 -0
- package/dist/daemon/io/index.js +24 -0
- package/dist/daemon/io/session-notes-loader.d.ts +4 -0
- package/dist/daemon/io/session-notes-loader.js +45 -0
- package/dist/daemon/io/soul-loader.d.ts +3 -0
- package/dist/daemon/io/soul-loader.js +68 -0
- package/dist/daemon/io/workspace-context-loader.d.ts +17 -0
- package/dist/daemon/io/workspace-context-loader.js +137 -0
- package/dist/daemon/runner/agent-loop-runner.d.ts +28 -0
- package/dist/daemon/runner/agent-loop-runner.js +250 -0
- package/dist/daemon/runner/construct-tools.d.ts +5 -0
- package/dist/daemon/runner/construct-tools.js +30 -0
- package/dist/daemon/runner/finalize-session.d.ts +3 -0
- package/dist/daemon/runner/finalize-session.js +75 -0
- package/dist/daemon/runner/index.d.ts +8 -0
- package/dist/daemon/runner/index.js +18 -0
- package/dist/daemon/runner/pre-agent-session.d.ts +7 -0
- package/dist/daemon/runner/pre-agent-session.js +227 -0
- package/dist/daemon/runner/runner-types.d.ts +73 -0
- package/dist/daemon/runner/runner-types.js +39 -0
- package/dist/daemon/runner/tool-schemas.d.ts +1 -0
- package/dist/daemon/runner/tool-schemas.js +151 -0
- package/dist/daemon/session-scope.d.ts +1 -1
- package/dist/daemon/startup-recovery.d.ts +20 -0
- package/dist/daemon/startup-recovery.js +323 -0
- package/dist/daemon/state/index.d.ts +6 -0
- package/dist/daemon/state/index.js +14 -0
- package/dist/daemon/state/session-state.d.ts +23 -0
- package/dist/daemon/state/session-state.js +44 -0
- package/dist/daemon/state/stuck-detection.d.ts +22 -0
- package/dist/daemon/state/stuck-detection.js +25 -0
- package/dist/daemon/state/terminal-signal.d.ts +9 -0
- package/dist/daemon/state/terminal-signal.js +10 -0
- package/dist/daemon/tools/file-tools.d.ts +1 -1
- package/dist/daemon/turn-end/detect-stuck.d.ts +2 -2
- package/dist/daemon/turn-end/detect-stuck.js +2 -2
- package/dist/daemon/turn-end/step-injector.d.ts +1 -1
- package/dist/daemon/types.d.ts +105 -0
- package/dist/daemon/types.js +11 -0
- package/dist/daemon/workflow-enricher.d.ts +16 -0
- package/dist/daemon/workflow-enricher.js +58 -0
- package/dist/daemon/workflow-runner.d.ts +13 -277
- package/dist/daemon/workflow-runner.js +63 -1421
- package/dist/manifest.json +280 -56
- package/dist/trigger/coordinator-deps.d.ts +1 -1
- package/dist/trigger/coordinator-deps.js +131 -0
- package/dist/trigger/delivery-client.d.ts +1 -1
- package/dist/trigger/delivery-pipeline.d.ts +1 -1
- package/dist/trigger/notification-service.d.ts +1 -1
- package/dist/trigger/trigger-listener.js +6 -2
- package/dist/trigger/trigger-router.d.ts +2 -2
- package/dist/v2/durable-core/domain/artifact-contract-validator.js +99 -0
- package/dist/v2/durable-core/schemas/artifacts/discovery-handoff.d.ts +39 -0
- package/dist/v2/durable-core/schemas/artifacts/discovery-handoff.js +10 -1
- package/dist/v2/durable-core/schemas/artifacts/index.d.ts +2 -1
- package/dist/v2/durable-core/schemas/artifacts/index.js +12 -1
- package/dist/v2/durable-core/schemas/artifacts/phase-handoff.d.ts +89 -0
- package/dist/v2/durable-core/schemas/artifacts/phase-handoff.js +56 -0
- package/docs/authoring-v2.md +12 -0
- package/docs/ideas/backlog.md +639 -25
- package/docs/reference/worktrain-daemon-invariants.md +33 -49
- package/docs/vision.md +5 -15
- package/package.json +2 -2
- package/workflows/coding-task-workflow-agentic.json +9 -6
- package/workflows/mr-review-workflow.agentic.v2.json +2 -2
- package/workflows/wr.discovery.json +2 -1
- package/workflows/wr.shaping.json +7 -4
- package/dist/console-ui/assets/index-BvBihscd.js +0 -28
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PipelineRunContextSchema = exports.ReviewPhaseRecordSchema = exports.CodingPhaseRecordSchema = exports.ShapingPhaseRecordSchema = exports.DiscoveryPhaseRecordSchema = exports.MIN_NOTES_LENGTH_FOR_PHASE_RESULT = void 0;
|
|
4
|
+
exports.buildPhaseResult = buildPhaseResult;
|
|
5
|
+
exports.parsePipelineRunContext = parsePipelineRunContext;
|
|
6
|
+
const zod_1 = require("zod");
|
|
7
|
+
const neverthrow_1 = require("neverthrow");
|
|
8
|
+
const index_js_1 = require("../v2/durable-core/schemas/artifacts/index.js");
|
|
9
|
+
exports.MIN_NOTES_LENGTH_FOR_PHASE_RESULT = 50;
|
|
10
|
+
function buildPhaseResult(artifact, recapMarkdown) {
|
|
11
|
+
if (artifact !== null) {
|
|
12
|
+
const maybeConf = artifact.confidenceBand;
|
|
13
|
+
const confidenceBand = maybeConf === 'high' || maybeConf === 'medium' || maybeConf === 'low'
|
|
14
|
+
? maybeConf
|
|
15
|
+
: null;
|
|
16
|
+
return { kind: 'full', artifact, confidenceBand, recapMarkdown };
|
|
17
|
+
}
|
|
18
|
+
if (recapMarkdown !== null && recapMarkdown.trim().length > exports.MIN_NOTES_LENGTH_FOR_PHASE_RESULT) {
|
|
19
|
+
return { kind: 'partial', recapMarkdown: recapMarkdown.trim() };
|
|
20
|
+
}
|
|
21
|
+
return { kind: 'fallback', recapMarkdown };
|
|
22
|
+
}
|
|
23
|
+
const PhaseResultFullDiscoverySchema = zod_1.z.object({
|
|
24
|
+
kind: zod_1.z.literal('full'),
|
|
25
|
+
artifact: index_js_1.DiscoveryHandoffArtifactV1Schema,
|
|
26
|
+
confidenceBand: zod_1.z.enum(['high', 'medium', 'low']).nullable(),
|
|
27
|
+
recapMarkdown: zod_1.z.string().nullable(),
|
|
28
|
+
});
|
|
29
|
+
const PhaseResultFullShapingSchema = zod_1.z.object({
|
|
30
|
+
kind: zod_1.z.literal('full'),
|
|
31
|
+
artifact: index_js_1.ShapingHandoffArtifactV1Schema,
|
|
32
|
+
confidenceBand: zod_1.z.enum(['high', 'medium', 'low']).nullable(),
|
|
33
|
+
recapMarkdown: zod_1.z.string().nullable(),
|
|
34
|
+
});
|
|
35
|
+
const PhaseResultFullCodingSchema = zod_1.z.object({
|
|
36
|
+
kind: zod_1.z.literal('full'),
|
|
37
|
+
artifact: index_js_1.CodingHandoffArtifactV1Schema,
|
|
38
|
+
confidenceBand: zod_1.z.enum(['high', 'medium', 'low']).nullable(),
|
|
39
|
+
recapMarkdown: zod_1.z.string().nullable(),
|
|
40
|
+
});
|
|
41
|
+
const PhaseResultFullReviewSchema = zod_1.z.object({
|
|
42
|
+
kind: zod_1.z.literal('full'),
|
|
43
|
+
artifact: index_js_1.ReviewVerdictArtifactV1Schema,
|
|
44
|
+
confidenceBand: zod_1.z.enum(['high', 'medium', 'low']).nullable(),
|
|
45
|
+
recapMarkdown: zod_1.z.string().nullable(),
|
|
46
|
+
});
|
|
47
|
+
const PhaseResultPartialSchema = zod_1.z.object({
|
|
48
|
+
kind: zod_1.z.literal('partial'),
|
|
49
|
+
recapMarkdown: zod_1.z.string(),
|
|
50
|
+
});
|
|
51
|
+
const PhaseResultFallbackSchema = zod_1.z.object({
|
|
52
|
+
kind: zod_1.z.literal('fallback'),
|
|
53
|
+
recapMarkdown: zod_1.z.string().nullable(),
|
|
54
|
+
});
|
|
55
|
+
exports.DiscoveryPhaseRecordSchema = zod_1.z.object({
|
|
56
|
+
completedAt: zod_1.z.string(),
|
|
57
|
+
sessionHandle: zod_1.z.string().min(1),
|
|
58
|
+
result: zod_1.z.discriminatedUnion('kind', [
|
|
59
|
+
PhaseResultFullDiscoverySchema,
|
|
60
|
+
PhaseResultPartialSchema,
|
|
61
|
+
PhaseResultFallbackSchema,
|
|
62
|
+
]),
|
|
63
|
+
});
|
|
64
|
+
exports.ShapingPhaseRecordSchema = zod_1.z.object({
|
|
65
|
+
completedAt: zod_1.z.string(),
|
|
66
|
+
sessionHandle: zod_1.z.string().min(1),
|
|
67
|
+
result: zod_1.z.discriminatedUnion('kind', [
|
|
68
|
+
PhaseResultFullShapingSchema,
|
|
69
|
+
PhaseResultPartialSchema,
|
|
70
|
+
PhaseResultFallbackSchema,
|
|
71
|
+
]),
|
|
72
|
+
});
|
|
73
|
+
exports.CodingPhaseRecordSchema = zod_1.z.object({
|
|
74
|
+
completedAt: zod_1.z.string(),
|
|
75
|
+
sessionHandle: zod_1.z.string().min(1),
|
|
76
|
+
result: zod_1.z.discriminatedUnion('kind', [
|
|
77
|
+
PhaseResultFullCodingSchema,
|
|
78
|
+
PhaseResultPartialSchema,
|
|
79
|
+
PhaseResultFallbackSchema,
|
|
80
|
+
]),
|
|
81
|
+
});
|
|
82
|
+
exports.ReviewPhaseRecordSchema = zod_1.z.object({
|
|
83
|
+
completedAt: zod_1.z.string(),
|
|
84
|
+
sessionHandle: zod_1.z.string().min(1),
|
|
85
|
+
result: zod_1.z.discriminatedUnion('kind', [
|
|
86
|
+
PhaseResultFullReviewSchema,
|
|
87
|
+
PhaseResultPartialSchema,
|
|
88
|
+
PhaseResultFallbackSchema,
|
|
89
|
+
]),
|
|
90
|
+
});
|
|
91
|
+
exports.PipelineRunContextSchema = zod_1.z.object({
|
|
92
|
+
runId: zod_1.z.string().min(1),
|
|
93
|
+
goal: zod_1.z.string().min(1),
|
|
94
|
+
workspace: zod_1.z.string().min(1),
|
|
95
|
+
startedAt: zod_1.z.string(),
|
|
96
|
+
pipelineMode: zod_1.z.enum(['FULL', 'IMPLEMENT', 'REVIEW_ONLY', 'QUICK_REVIEW']),
|
|
97
|
+
status: zod_1.z.enum(['in_progress', 'completed']).optional(),
|
|
98
|
+
phases: zod_1.z.object({
|
|
99
|
+
discovery: exports.DiscoveryPhaseRecordSchema.optional(),
|
|
100
|
+
shaping: exports.ShapingPhaseRecordSchema.optional(),
|
|
101
|
+
coding: exports.CodingPhaseRecordSchema.optional(),
|
|
102
|
+
review: exports.ReviewPhaseRecordSchema.optional(),
|
|
103
|
+
}),
|
|
104
|
+
});
|
|
105
|
+
function parsePipelineRunContext(raw) {
|
|
106
|
+
const result = exports.PipelineRunContextSchema.safeParse(raw);
|
|
107
|
+
if (!result.success) {
|
|
108
|
+
const issues = result.error.issues
|
|
109
|
+
.map((i) => `${i.path.join('.')}: ${i.message}`)
|
|
110
|
+
.join('; ');
|
|
111
|
+
return (0, neverthrow_1.err)(`PipelineRunContext parse failed: ${issues}`);
|
|
112
|
+
}
|
|
113
|
+
return (0, neverthrow_1.ok)(result.data);
|
|
114
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
2
|
+
import { AnthropicBedrock } from '@anthropic-ai/bedrock-sdk';
|
|
3
|
+
import type { WorkflowTrigger } from '../types.js';
|
|
4
|
+
export declare function buildAgentClient(trigger: WorkflowTrigger, apiKey: string, env: NodeJS.ProcessEnv): {
|
|
5
|
+
agentClient: Anthropic | AnthropicBedrock;
|
|
6
|
+
modelId: string;
|
|
7
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.buildAgentClient = buildAgentClient;
|
|
7
|
+
const sdk_1 = __importDefault(require("@anthropic-ai/sdk"));
|
|
8
|
+
const bedrock_sdk_1 = require("@anthropic-ai/bedrock-sdk");
|
|
9
|
+
function buildAgentClient(trigger, apiKey, env) {
|
|
10
|
+
if (trigger.agentConfig?.model) {
|
|
11
|
+
const slashIdx = trigger.agentConfig.model.indexOf('/');
|
|
12
|
+
if (slashIdx === -1) {
|
|
13
|
+
throw new Error(`agentConfig.model must be in "provider/model-id" format, got: "${trigger.agentConfig.model}"`);
|
|
14
|
+
}
|
|
15
|
+
const provider = trigger.agentConfig.model.slice(0, slashIdx);
|
|
16
|
+
const modelId = trigger.agentConfig.model.slice(slashIdx + 1);
|
|
17
|
+
const agentClient = provider === 'amazon-bedrock' ? new bedrock_sdk_1.AnthropicBedrock() : new sdk_1.default({ apiKey });
|
|
18
|
+
return { agentClient, modelId };
|
|
19
|
+
}
|
|
20
|
+
const usesBedrock = !!env['AWS_PROFILE'] || !!env['AWS_ACCESS_KEY_ID'];
|
|
21
|
+
if (usesBedrock) {
|
|
22
|
+
return {
|
|
23
|
+
agentClient: new bedrock_sdk_1.AnthropicBedrock(),
|
|
24
|
+
modelId: 'us.anthropic.claude-sonnet-4-6',
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
agentClient: new sdk_1.default({ apiKey }),
|
|
29
|
+
modelId: 'claude-sonnet-4-6',
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { BASE_SYSTEM_PROMPT, buildSessionRecap, buildSystemPrompt, DAEMON_SOUL_DEFAULT } from './system-prompt.js';
|
|
2
|
+
export type { SessionContext } from './session-context.js';
|
|
3
|
+
export { DEFAULT_SESSION_TIMEOUT_MINUTES, DEFAULT_MAX_TURNS, DEFAULT_STALL_TIMEOUT_SECONDS, buildSessionContext, } from './session-context.js';
|
|
4
|
+
export type { SidecarLifecycle } from './session-result.js';
|
|
5
|
+
export { tagToStatsOutcome, sidecardLifecycleFor, buildSessionResult } from './session-result.js';
|
|
6
|
+
export { buildAgentClient } from './agent-client.js';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildAgentClient = exports.buildSessionResult = exports.sidecardLifecycleFor = exports.tagToStatsOutcome = exports.buildSessionContext = exports.DEFAULT_STALL_TIMEOUT_SECONDS = exports.DEFAULT_MAX_TURNS = exports.DEFAULT_SESSION_TIMEOUT_MINUTES = exports.DAEMON_SOUL_DEFAULT = exports.buildSystemPrompt = exports.buildSessionRecap = exports.BASE_SYSTEM_PROMPT = void 0;
|
|
4
|
+
var system_prompt_js_1 = require("./system-prompt.js");
|
|
5
|
+
Object.defineProperty(exports, "BASE_SYSTEM_PROMPT", { enumerable: true, get: function () { return system_prompt_js_1.BASE_SYSTEM_PROMPT; } });
|
|
6
|
+
Object.defineProperty(exports, "buildSessionRecap", { enumerable: true, get: function () { return system_prompt_js_1.buildSessionRecap; } });
|
|
7
|
+
Object.defineProperty(exports, "buildSystemPrompt", { enumerable: true, get: function () { return system_prompt_js_1.buildSystemPrompt; } });
|
|
8
|
+
Object.defineProperty(exports, "DAEMON_SOUL_DEFAULT", { enumerable: true, get: function () { return system_prompt_js_1.DAEMON_SOUL_DEFAULT; } });
|
|
9
|
+
var session_context_js_1 = require("./session-context.js");
|
|
10
|
+
Object.defineProperty(exports, "DEFAULT_SESSION_TIMEOUT_MINUTES", { enumerable: true, get: function () { return session_context_js_1.DEFAULT_SESSION_TIMEOUT_MINUTES; } });
|
|
11
|
+
Object.defineProperty(exports, "DEFAULT_MAX_TURNS", { enumerable: true, get: function () { return session_context_js_1.DEFAULT_MAX_TURNS; } });
|
|
12
|
+
Object.defineProperty(exports, "DEFAULT_STALL_TIMEOUT_SECONDS", { enumerable: true, get: function () { return session_context_js_1.DEFAULT_STALL_TIMEOUT_SECONDS; } });
|
|
13
|
+
Object.defineProperty(exports, "buildSessionContext", { enumerable: true, get: function () { return session_context_js_1.buildSessionContext; } });
|
|
14
|
+
var session_result_js_1 = require("./session-result.js");
|
|
15
|
+
Object.defineProperty(exports, "tagToStatsOutcome", { enumerable: true, get: function () { return session_result_js_1.tagToStatsOutcome; } });
|
|
16
|
+
Object.defineProperty(exports, "sidecardLifecycleFor", { enumerable: true, get: function () { return session_result_js_1.sidecardLifecycleFor; } });
|
|
17
|
+
Object.defineProperty(exports, "buildSessionResult", { enumerable: true, get: function () { return session_result_js_1.buildSessionResult; } });
|
|
18
|
+
var agent_client_js_1 = require("./agent-client.js");
|
|
19
|
+
Object.defineProperty(exports, "buildAgentClient", { enumerable: true, get: function () { return agent_client_js_1.buildAgentClient; } });
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { WorkflowTrigger } from '../types.js';
|
|
2
|
+
import type { ContextBundle } from '../context-loader.js';
|
|
3
|
+
import type { EnricherResult } from '../workflow-enricher.js';
|
|
4
|
+
export declare const DEFAULT_SESSION_TIMEOUT_MINUTES = 30;
|
|
5
|
+
export declare const DEFAULT_MAX_TURNS = 200;
|
|
6
|
+
export declare const DEFAULT_STALL_TIMEOUT_SECONDS = 120;
|
|
7
|
+
export interface SessionContext {
|
|
8
|
+
readonly systemPrompt: string;
|
|
9
|
+
readonly initialPrompt: string;
|
|
10
|
+
readonly sessionTimeoutMs: number;
|
|
11
|
+
readonly maxTurns: number;
|
|
12
|
+
readonly stallTimeoutMs: number;
|
|
13
|
+
}
|
|
14
|
+
export declare function buildSessionContext(trigger: WorkflowTrigger, context: ContextBundle, firstStepPrompt: string, effectiveWorkspacePath: string, enricherResult?: EnricherResult): SessionContext;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_STALL_TIMEOUT_SECONDS = exports.DEFAULT_MAX_TURNS = exports.DEFAULT_SESSION_TIMEOUT_MINUTES = void 0;
|
|
4
|
+
exports.buildSessionContext = buildSessionContext;
|
|
5
|
+
const system_prompt_js_1 = require("./system-prompt.js");
|
|
6
|
+
exports.DEFAULT_SESSION_TIMEOUT_MINUTES = 30;
|
|
7
|
+
exports.DEFAULT_MAX_TURNS = 200;
|
|
8
|
+
exports.DEFAULT_STALL_TIMEOUT_SECONDS = 120;
|
|
9
|
+
function buildSessionContext(trigger, context, firstStepPrompt, effectiveWorkspacePath, enricherResult) {
|
|
10
|
+
const workspaceContext = context.workspaceRules[0]?.content ?? null;
|
|
11
|
+
const sessionNotes = context.sessionHistory.map((n) => n.content);
|
|
12
|
+
const sessionState = (0, system_prompt_js_1.buildSessionRecap)(sessionNotes);
|
|
13
|
+
const systemPrompt = (0, system_prompt_js_1.buildSystemPrompt)(trigger, sessionState, context.soulContent, workspaceContext, effectiveWorkspacePath, enricherResult);
|
|
14
|
+
const contextJson = trigger.context
|
|
15
|
+
? `\n\nTrigger context:\n\`\`\`json\n${JSON.stringify(trigger.context, null, 2)}\n\`\`\``
|
|
16
|
+
: '';
|
|
17
|
+
const initialPrompt = firstStepPrompt +
|
|
18
|
+
contextJson +
|
|
19
|
+
'\n\nComplete all step work, then call complete_step with your notes to advance.';
|
|
20
|
+
const sessionTimeoutMs = (trigger.agentConfig?.maxSessionMinutes ?? exports.DEFAULT_SESSION_TIMEOUT_MINUTES) * 60 * 1000;
|
|
21
|
+
const maxTurns = trigger.agentConfig?.maxTurns ?? exports.DEFAULT_MAX_TURNS;
|
|
22
|
+
const stallTimeoutMs = (trigger.agentConfig?.stallTimeoutSeconds ?? exports.DEFAULT_STALL_TIMEOUT_SECONDS) * 1000;
|
|
23
|
+
return { systemPrompt, initialPrompt, sessionTimeoutMs, maxTurns, stallTimeoutMs };
|
|
24
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { WorkflowTrigger, WorkflowRunResult } from '../types.js';
|
|
2
|
+
import type { SessionState } from '../state/session-state.js';
|
|
3
|
+
export declare function tagToStatsOutcome(tag: WorkflowRunResult['_tag']): 'success' | 'error' | 'timeout' | 'stuck';
|
|
4
|
+
export type SidecarLifecycle = {
|
|
5
|
+
readonly kind: 'delete_now';
|
|
6
|
+
} | {
|
|
7
|
+
readonly kind: 'retain_for_delivery';
|
|
8
|
+
};
|
|
9
|
+
export declare function sidecardLifecycleFor(tag: WorkflowRunResult['_tag'], branchStrategy: WorkflowTrigger['branchStrategy']): SidecarLifecycle;
|
|
10
|
+
export declare function buildSessionResult(state: Readonly<SessionState>, stopReason: string, errorMessage: string | undefined, trigger: WorkflowTrigger, sessionId: string, sessionWorktreePath: string | undefined): WorkflowRunResult;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.tagToStatsOutcome = tagToStatsOutcome;
|
|
4
|
+
exports.sidecardLifecycleFor = sidecardLifecycleFor;
|
|
5
|
+
exports.buildSessionResult = buildSessionResult;
|
|
6
|
+
const assert_never_js_1 = require("../../runtime/assert-never.js");
|
|
7
|
+
const session_context_js_1 = require("./session-context.js");
|
|
8
|
+
function tagToStatsOutcome(tag) {
|
|
9
|
+
switch (tag) {
|
|
10
|
+
case 'success': return 'success';
|
|
11
|
+
case 'error': return 'error';
|
|
12
|
+
case 'timeout': return 'timeout';
|
|
13
|
+
case 'stuck': return 'stuck';
|
|
14
|
+
case 'delivery_failed': return 'success';
|
|
15
|
+
default: return (0, assert_never_js_1.assertNever)(tag);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function sidecardLifecycleFor(tag, branchStrategy) {
|
|
19
|
+
switch (tag) {
|
|
20
|
+
case 'success':
|
|
21
|
+
return branchStrategy === 'worktree'
|
|
22
|
+
? { kind: 'retain_for_delivery' }
|
|
23
|
+
: { kind: 'delete_now' };
|
|
24
|
+
case 'error':
|
|
25
|
+
case 'timeout':
|
|
26
|
+
case 'stuck':
|
|
27
|
+
return { kind: 'delete_now' };
|
|
28
|
+
case 'delivery_failed':
|
|
29
|
+
throw new Error(`sidecardLifecycleFor: delivery_failed is not a valid input (invariant 1.2)`);
|
|
30
|
+
default:
|
|
31
|
+
return (0, assert_never_js_1.assertNever)(tag);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function buildSessionResult(state, stopReason, errorMessage, trigger, sessionId, sessionWorktreePath) {
|
|
35
|
+
if (state.terminalSignal !== null) {
|
|
36
|
+
const signal = state.terminalSignal;
|
|
37
|
+
if (signal.kind === 'stuck') {
|
|
38
|
+
return {
|
|
39
|
+
_tag: 'stuck',
|
|
40
|
+
workflowId: trigger.workflowId,
|
|
41
|
+
reason: signal.reason,
|
|
42
|
+
message: `Session aborted: stuck heuristic fired (${signal.reason})`,
|
|
43
|
+
stopReason: 'aborted',
|
|
44
|
+
...(state.issueSummaries.length > 0 ? { issueSummaries: [...state.issueSummaries] } : {}),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
if (signal.kind === 'timeout') {
|
|
48
|
+
const limitDescription = signal.reason === 'wall_clock'
|
|
49
|
+
? `${trigger.agentConfig?.maxSessionMinutes ?? session_context_js_1.DEFAULT_SESSION_TIMEOUT_MINUTES} minutes`
|
|
50
|
+
: `${trigger.agentConfig?.maxTurns ?? session_context_js_1.DEFAULT_MAX_TURNS} turns`;
|
|
51
|
+
return {
|
|
52
|
+
_tag: 'timeout',
|
|
53
|
+
workflowId: trigger.workflowId,
|
|
54
|
+
reason: signal.reason,
|
|
55
|
+
message: `Workflow ${signal.reason === 'wall_clock' ? 'timed out' : 'exceeded turn limit'} after ${limitDescription}`,
|
|
56
|
+
stopReason: 'aborted',
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return (0, assert_never_js_1.assertNever)(signal);
|
|
60
|
+
}
|
|
61
|
+
if (stopReason === 'error' || errorMessage) {
|
|
62
|
+
const errMsg = errorMessage ?? 'Agent stopped with error reason';
|
|
63
|
+
const lastToolCalled = state.lastNToolCalls.length > 0 ? state.lastNToolCalls[state.lastNToolCalls.length - 1] : null;
|
|
64
|
+
const stuckMarker = `\n\nWORKTRAIN_STUCK: ${JSON.stringify({
|
|
65
|
+
reason: 'session_error',
|
|
66
|
+
error: errMsg.slice(0, 500),
|
|
67
|
+
workflowId: trigger.workflowId,
|
|
68
|
+
sessionId,
|
|
69
|
+
turnCount: state.turnCount,
|
|
70
|
+
stepAdvanceCount: state.stepAdvanceCount,
|
|
71
|
+
...(lastToolCalled !== null && { lastToolCalled }),
|
|
72
|
+
...(state.issueSummaries.length > 0 && { issueSummaries: state.issueSummaries }),
|
|
73
|
+
})}`;
|
|
74
|
+
return {
|
|
75
|
+
_tag: 'error',
|
|
76
|
+
workflowId: trigger.workflowId,
|
|
77
|
+
message: errMsg,
|
|
78
|
+
stopReason,
|
|
79
|
+
lastStepNotes: stuckMarker,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
_tag: 'success',
|
|
84
|
+
workflowId: trigger.workflowId,
|
|
85
|
+
stopReason,
|
|
86
|
+
...(state.lastStepNotes !== undefined ? { lastStepNotes: state.lastStepNotes } : {}),
|
|
87
|
+
...(state.lastStepArtifacts !== undefined ? { lastStepArtifacts: state.lastStepArtifacts } : {}),
|
|
88
|
+
...(sessionWorktreePath !== undefined ? { sessionWorkspacePath: sessionWorktreePath } : {}),
|
|
89
|
+
...(sessionWorktreePath !== undefined ? { sessionId } : {}),
|
|
90
|
+
...(trigger.botIdentity !== undefined ? { botIdentity: trigger.botIdentity } : {}),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { WorkflowTrigger } from '../types.js';
|
|
2
|
+
import type { EnricherResult } from '../workflow-enricher.js';
|
|
3
|
+
export { DAEMON_SOUL_DEFAULT } from '../soul-template.js';
|
|
4
|
+
export declare const BASE_SYSTEM_PROMPT = "You are WorkRail Auto, an autonomous agent that executes workflows step by step. You are running unattended -- there is no user watching. Your entire job is to faithfully complete the current workflow.\n\n## What you are\nYou are highly capable. You handle ambitious, multi-step tasks that require real codebase understanding. You don't hedge, ask for permission, or stop to check in. You work.\n\n## Your oracle (consult in this order when uncertain)\n1. The daemon soul rules (## Agent Rules and Philosophy below)\n2. AGENTS.md / CLAUDE.md in the workspace (injected below under Workspace Context)\n3. The current workflow step's prompt and guidance\n4. Local code patterns in the relevant module (grep the directory, not the whole repo)\n5. Industry best practices -- only when nothing above applies\n\n## Self-directed reasoning\nAsk yourself questions to clarify your approach, then answer them yourself using tools before acting. Never wait for a human to answer -- you are the oracle.\n\nBad pattern: \"I'll analyze both layers.\" (no justification)\nGood pattern: \"Question: Should I check the middleware? Answer: The workflow step says 'trace the full call chain', and the AGENTS.md says the entry point is in the middleware layer. Yes, start there.\"\n\n## Your tools\n- `complete_step`: Mark the current step complete and advance to the next one. Call this after completing ALL work required by the step. Include your notes (min 50 characters) in the notes field. The daemon manages the session token internally -- you do NOT need a continueToken. This is the preferred advancement tool for daemon sessions.\n- `continue_workflow`: [DEPRECATED -- use complete_step instead. Do NOT pass a continueToken.] Only use this if complete_step is unavailable.\n- `Bash`: Run shell commands. Use for building, testing, running scripts.\n- `Read`: Read files.\n- `Write`: Write files.\n- `report_issue`: Record a structured issue, error, or unexpected behavior. Call this AND complete_step (unless fatal). Does not stop the session -- it creates a record for the auto-fix coordinator.\n- `spawn_agent`: Delegate a sub-task to a child WorkRail session. BLOCKS until the child completes. Returns `{ childSessionId, outcome: \"success\"|\"error\"|\"timeout\", notes: string }`. Always check `outcome` before using `notes`. IMPORTANT: your session's time limit (maxSessionMinutes) keeps running while the child executes -- ensure your parent session has enough time for both your work AND the child's work. Maximum spawn depth is 3 by default (configurable). Use only when a step explicitly asks for delegation or when a clearly separable sub-task would benefit from its own WorkRail audit trail.\n- `signal_coordinator`: Emit a structured mid-session signal to the coordinator WITHOUT advancing the workflow step. Use when the step asks you to surface a finding, request data, request approval, or report a blocking condition. Always returns immediately -- fire-and-observe. Signal kinds: \"progress\", \"finding\", \"data_needed\", \"approval_needed\", \"blocked\".\n\n## Execution contract\n1. Read the step carefully. Do ALL the work the step asks for.\n2. Call `complete_step` with your notes. No continueToken needed -- the daemon manages it.\n3. Repeat until the workflow reports it is complete.\n4. Do NOT skip steps. Do NOT call `complete_step` without completing the step's work.\n\n## The workflow is the contract\nEvery step must be fully completed before you call complete_step. The workflow step prompt is the specification of what 'done' means -- not a suggestion. Don't advance until the work is actually done.\n\nYour cognitive mode changes per step: some steps make you a researcher, others a reviewer, others an implementer. Adopt the mode the step describes. Don't bring your own agenda.\n\n## Silent failure is the worst outcome\nIf something goes wrong: call report_issue, then continue unless severity is 'fatal'. Do NOT silently retry forever, work around failures without noting them, or pretend things worked. The issue record is how the system learns and self-heals.\n\n## Tools are your hands, not your voice\nDon't narrate what you're about to do. Use the tool and report what you found. Token efficiency matters -- you have a wall-clock timeout.\n\n## You don't have a user. You have a workflow and a soul.\nIf you're unsure, consult the oracle above. If nothing answers the question, make a reasoned decision, call report_issue with kind='self_correction' to document it, and continue.\n\n## IMPORTANT: Never use continue_workflow in daemon sessions\ncomplete_step is your advancement tool. It does not require a continueToken. Do NOT call continue_workflow with a token you found in a previous message -- use complete_step instead.";
|
|
5
|
+
export declare function buildSessionRecap(notes: readonly string[]): string;
|
|
6
|
+
export declare function buildSystemPrompt(trigger: WorkflowTrigger, sessionState: string, soulContent: string, workspaceContext: string | null, effectiveWorkspacePath: string, enricherResult?: EnricherResult): string;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BASE_SYSTEM_PROMPT = exports.DAEMON_SOUL_DEFAULT = void 0;
|
|
4
|
+
exports.buildSessionRecap = buildSessionRecap;
|
|
5
|
+
exports.buildSystemPrompt = buildSystemPrompt;
|
|
6
|
+
const types_js_1 = require("../types.js");
|
|
7
|
+
var soul_template_js_1 = require("../soul-template.js");
|
|
8
|
+
Object.defineProperty(exports, "DAEMON_SOUL_DEFAULT", { enumerable: true, get: function () { return soul_template_js_1.DAEMON_SOUL_DEFAULT; } });
|
|
9
|
+
const MAX_ASSEMBLED_CONTEXT_BYTES = 8192;
|
|
10
|
+
exports.BASE_SYSTEM_PROMPT = `\
|
|
11
|
+
You are WorkRail Auto, an autonomous agent that executes workflows step by step. You are running unattended -- there is no user watching. Your entire job is to faithfully complete the current workflow.
|
|
12
|
+
|
|
13
|
+
## What you are
|
|
14
|
+
You are highly capable. You handle ambitious, multi-step tasks that require real codebase understanding. You don't hedge, ask for permission, or stop to check in. You work.
|
|
15
|
+
|
|
16
|
+
## Your oracle (consult in this order when uncertain)
|
|
17
|
+
1. The daemon soul rules (## Agent Rules and Philosophy below)
|
|
18
|
+
2. AGENTS.md / CLAUDE.md in the workspace (injected below under Workspace Context)
|
|
19
|
+
3. The current workflow step's prompt and guidance
|
|
20
|
+
4. Local code patterns in the relevant module (grep the directory, not the whole repo)
|
|
21
|
+
5. Industry best practices -- only when nothing above applies
|
|
22
|
+
|
|
23
|
+
## Self-directed reasoning
|
|
24
|
+
Ask yourself questions to clarify your approach, then answer them yourself using tools before acting. Never wait for a human to answer -- you are the oracle.
|
|
25
|
+
|
|
26
|
+
Bad pattern: "I'll analyze both layers." (no justification)
|
|
27
|
+
Good pattern: "Question: Should I check the middleware? Answer: The workflow step says 'trace the full call chain', and the AGENTS.md says the entry point is in the middleware layer. Yes, start there."
|
|
28
|
+
|
|
29
|
+
## Your tools
|
|
30
|
+
- \`complete_step\`: Mark the current step complete and advance to the next one. Call this after completing ALL work required by the step. Include your notes (min 50 characters) in the notes field. The daemon manages the session token internally -- you do NOT need a continueToken. This is the preferred advancement tool for daemon sessions.
|
|
31
|
+
- \`continue_workflow\`: [DEPRECATED -- use complete_step instead. Do NOT pass a continueToken.] Only use this if complete_step is unavailable.
|
|
32
|
+
- \`Bash\`: Run shell commands. Use for building, testing, running scripts.
|
|
33
|
+
- \`Read\`: Read files.
|
|
34
|
+
- \`Write\`: Write files.
|
|
35
|
+
- \`report_issue\`: Record a structured issue, error, or unexpected behavior. Call this AND complete_step (unless fatal). Does not stop the session -- it creates a record for the auto-fix coordinator.
|
|
36
|
+
- \`spawn_agent\`: Delegate a sub-task to a child WorkRail session. BLOCKS until the child completes. Returns \`{ childSessionId, outcome: "success"|"error"|"timeout", notes: string }\`. Always check \`outcome\` before using \`notes\`. IMPORTANT: your session's time limit (maxSessionMinutes) keeps running while the child executes -- ensure your parent session has enough time for both your work AND the child's work. Maximum spawn depth is 3 by default (configurable). Use only when a step explicitly asks for delegation or when a clearly separable sub-task would benefit from its own WorkRail audit trail.
|
|
37
|
+
- \`signal_coordinator\`: Emit a structured mid-session signal to the coordinator WITHOUT advancing the workflow step. Use when the step asks you to surface a finding, request data, request approval, or report a blocking condition. Always returns immediately -- fire-and-observe. Signal kinds: "progress", "finding", "data_needed", "approval_needed", "blocked".
|
|
38
|
+
|
|
39
|
+
## Execution contract
|
|
40
|
+
1. Read the step carefully. Do ALL the work the step asks for.
|
|
41
|
+
2. Call \`complete_step\` with your notes. No continueToken needed -- the daemon manages it.
|
|
42
|
+
3. Repeat until the workflow reports it is complete.
|
|
43
|
+
4. Do NOT skip steps. Do NOT call \`complete_step\` without completing the step's work.
|
|
44
|
+
|
|
45
|
+
## The workflow is the contract
|
|
46
|
+
Every step must be fully completed before you call complete_step. The workflow step prompt is the specification of what 'done' means -- not a suggestion. Don't advance until the work is actually done.
|
|
47
|
+
|
|
48
|
+
Your cognitive mode changes per step: some steps make you a researcher, others a reviewer, others an implementer. Adopt the mode the step describes. Don't bring your own agenda.
|
|
49
|
+
|
|
50
|
+
## Silent failure is the worst outcome
|
|
51
|
+
If something goes wrong: call report_issue, then continue unless severity is 'fatal'. Do NOT silently retry forever, work around failures without noting them, or pretend things worked. The issue record is how the system learns and self-heals.
|
|
52
|
+
|
|
53
|
+
## Tools are your hands, not your voice
|
|
54
|
+
Don't narrate what you're about to do. Use the tool and report what you found. Token efficiency matters -- you have a wall-clock timeout.
|
|
55
|
+
|
|
56
|
+
## You don't have a user. You have a workflow and a soul.
|
|
57
|
+
If you're unsure, consult the oracle above. If nothing answers the question, make a reasoned decision, call report_issue with kind='self_correction' to document it, and continue.
|
|
58
|
+
|
|
59
|
+
## IMPORTANT: Never use continue_workflow in daemon sessions
|
|
60
|
+
complete_step is your advancement tool. It does not require a continueToken. Do NOT call continue_workflow with a token you found in a previous message -- use complete_step instead.\
|
|
61
|
+
`;
|
|
62
|
+
function truncateToByteLimit(s, maxBytes, marker) {
|
|
63
|
+
if (Buffer.byteLength(s, 'utf8') <= maxBytes)
|
|
64
|
+
return s;
|
|
65
|
+
let end = maxBytes;
|
|
66
|
+
while (end > 0 && Buffer.byteLength(s.slice(0, end), 'utf8') > maxBytes)
|
|
67
|
+
end--;
|
|
68
|
+
while (end > 0) {
|
|
69
|
+
const code = s.charCodeAt(end - 1);
|
|
70
|
+
if (code >= 0xD800 && code <= 0xDFFF) {
|
|
71
|
+
end--;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const newlineIdx = s.lastIndexOf('\n', end);
|
|
78
|
+
return (newlineIdx > 0 ? s.slice(0, newlineIdx) : s.slice(0, end)) + '\n' + marker;
|
|
79
|
+
}
|
|
80
|
+
function buildSessionRecap(notes) {
|
|
81
|
+
if (notes.length === 0)
|
|
82
|
+
return '';
|
|
83
|
+
const formattedNotes = notes
|
|
84
|
+
.map((note, i) => `### Prior step ${i + 1}\n${note}`)
|
|
85
|
+
.join('\n\n');
|
|
86
|
+
return `<workrail_session_state>\nThe following notes summarize prior steps from this session:\n\n${formattedNotes}\n</workrail_session_state>`;
|
|
87
|
+
}
|
|
88
|
+
const MAX_GIT_DIFF_STAT_BYTES = 2048;
|
|
89
|
+
function sectionWorktreeScope(trigger, effectiveWorkspacePath) {
|
|
90
|
+
if (effectiveWorkspacePath === trigger.workspacePath)
|
|
91
|
+
return [];
|
|
92
|
+
return [
|
|
93
|
+
'',
|
|
94
|
+
`**Worktree session scope:** Your workspace is the isolated git worktree at \`${effectiveWorkspacePath}\`. Do not access, read, or modify the main checkout at \`${trigger.workspacePath}\`. Do not read planning docs, roadmap files, or backlog files. All Bash commands, file reads, and file writes must stay within your worktree path.`,
|
|
95
|
+
];
|
|
96
|
+
}
|
|
97
|
+
function sectionWorkspaceContext(workspaceContext) {
|
|
98
|
+
if (workspaceContext === null)
|
|
99
|
+
return [];
|
|
100
|
+
return ['', '## Workspace Context (from AGENTS.md / CLAUDE.md)', workspaceContext];
|
|
101
|
+
}
|
|
102
|
+
function sectionAssembledContext(assembledContextSummary) {
|
|
103
|
+
if (!assembledContextSummary || assembledContextSummary.trim().length === 0)
|
|
104
|
+
return [];
|
|
105
|
+
const ctxStr = truncateToByteLimit(assembledContextSummary, MAX_ASSEMBLED_CONTEXT_BYTES, '[Prior context truncated at 8KB]');
|
|
106
|
+
return ['', '## Prior Context', ctxStr.trim()];
|
|
107
|
+
}
|
|
108
|
+
function sectionPriorWorkspaceNotes(assembledContextSummary, enricherResult) {
|
|
109
|
+
if (!enricherResult || enricherResult.priorSessionNotes.length === 0)
|
|
110
|
+
return [];
|
|
111
|
+
if (assembledContextSummary && assembledContextSummary.trim().length > 0)
|
|
112
|
+
return [];
|
|
113
|
+
const noteLines = enricherResult.priorSessionNotes.map((note) => {
|
|
114
|
+
const title = note.sessionTitle ?? note.sessionId.slice(0, 12);
|
|
115
|
+
const branch = note.gitBranch ? ` (${note.gitBranch})` : '';
|
|
116
|
+
const recap = note.recapSnippet ?? '(no recap)';
|
|
117
|
+
return `**${title}**${branch}: ${recap}`;
|
|
118
|
+
});
|
|
119
|
+
return ['', '## Prior Workspace Notes', ...noteLines];
|
|
120
|
+
}
|
|
121
|
+
function sectionChangedFiles(enricherResult) {
|
|
122
|
+
if (!enricherResult || enricherResult.gitDiffStat === null)
|
|
123
|
+
return [];
|
|
124
|
+
const diffStat = Buffer.byteLength(enricherResult.gitDiffStat, 'utf8') > MAX_GIT_DIFF_STAT_BYTES
|
|
125
|
+
? new TextDecoder().decode(Buffer.from(enricherResult.gitDiffStat, 'utf8').subarray(0, MAX_GIT_DIFF_STAT_BYTES)) + '\n[diff stat truncated]'
|
|
126
|
+
: enricherResult.gitDiffStat;
|
|
127
|
+
return ['', '## Changed files', '```', diffStat, '```'];
|
|
128
|
+
}
|
|
129
|
+
function sectionReferenceUrls(trigger) {
|
|
130
|
+
if (!trigger.referenceUrls || trigger.referenceUrls.length === 0)
|
|
131
|
+
return [];
|
|
132
|
+
return [
|
|
133
|
+
'',
|
|
134
|
+
'## Reference documents',
|
|
135
|
+
'Before starting, fetch and read these reference documents: ' + trigger.referenceUrls.join(' '),
|
|
136
|
+
'If you cannot fetch any of these documents, note their unavailability and proceed.',
|
|
137
|
+
];
|
|
138
|
+
}
|
|
139
|
+
function buildSystemPrompt(trigger, sessionState, soulContent, workspaceContext, effectiveWorkspacePath, enricherResult) {
|
|
140
|
+
const { assembledContextSummary } = (0, types_js_1.extractContextSlots)(trigger.context);
|
|
141
|
+
const sections = [
|
|
142
|
+
[exports.BASE_SYSTEM_PROMPT, '', `<workrail_session_state>${sessionState}</workrail_session_state>`, '', '## Agent Rules and Philosophy', soulContent, '', `## Workspace: ${effectiveWorkspacePath}`],
|
|
143
|
+
sectionWorktreeScope(trigger, effectiveWorkspacePath),
|
|
144
|
+
sectionWorkspaceContext(workspaceContext),
|
|
145
|
+
sectionAssembledContext(assembledContextSummary),
|
|
146
|
+
sectionPriorWorkspaceNotes(assembledContextSummary, enricherResult),
|
|
147
|
+
sectionChangedFiles(enricherResult),
|
|
148
|
+
sectionReferenceUrls(trigger),
|
|
149
|
+
];
|
|
150
|
+
return sections.flat().join('\n');
|
|
151
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.appendConversationMessages = appendConversationMessages;
|
|
37
|
+
const fs = __importStar(require("node:fs/promises"));
|
|
38
|
+
const path = __importStar(require("node:path"));
|
|
39
|
+
async function appendConversationMessages(filePath, messages) {
|
|
40
|
+
if (messages.length === 0)
|
|
41
|
+
return;
|
|
42
|
+
const lines = messages.map((m) => JSON.stringify(m)).join('\n') + '\n';
|
|
43
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
44
|
+
await fs.appendFile(filePath, lines, 'utf8');
|
|
45
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const DAEMON_STATS_DIR: string;
|
|
2
|
+
export declare function writeExecutionStats(statsDir: string, sessionId: string, workflowId: string, startMs: number, outcome: 'success' | 'error' | 'timeout' | 'stuck' | 'unknown', stepCount: number): void;
|
|
3
|
+
export declare function writeStuckOutboxEntry(opts: {
|
|
4
|
+
workflowId: string;
|
|
5
|
+
reason: 'repeated_tool_call' | 'no_progress' | 'stall';
|
|
6
|
+
issueSummaries?: readonly string[];
|
|
7
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.DAEMON_STATS_DIR = void 0;
|
|
37
|
+
exports.writeExecutionStats = writeExecutionStats;
|
|
38
|
+
exports.writeStuckOutboxEntry = writeStuckOutboxEntry;
|
|
39
|
+
const fs = __importStar(require("node:fs/promises"));
|
|
40
|
+
const path = __importStar(require("node:path"));
|
|
41
|
+
const os = __importStar(require("node:os"));
|
|
42
|
+
const node_crypto_1 = require("node:crypto");
|
|
43
|
+
const stats_summary_js_1 = require("../stats-summary.js");
|
|
44
|
+
exports.DAEMON_STATS_DIR = path.join(os.homedir(), '.workrail', 'data');
|
|
45
|
+
function writeExecutionStats(statsDir, sessionId, workflowId, startMs, outcome, stepCount) {
|
|
46
|
+
const endMs = Date.now();
|
|
47
|
+
const statsPath = path.join(statsDir, 'execution-stats.jsonl');
|
|
48
|
+
fs.mkdir(statsDir, { recursive: true })
|
|
49
|
+
.then(() => fs.appendFile(statsPath, JSON.stringify({
|
|
50
|
+
sessionId,
|
|
51
|
+
workflowId,
|
|
52
|
+
startMs,
|
|
53
|
+
endMs,
|
|
54
|
+
durationMs: endMs - startMs,
|
|
55
|
+
outcome,
|
|
56
|
+
stepCount,
|
|
57
|
+
ts: new Date().toISOString(),
|
|
58
|
+
}) + '\n', 'utf8'))
|
|
59
|
+
.then(() => { (0, stats_summary_js_1.writeStatsSummary)(statsDir).catch(() => { }); })
|
|
60
|
+
.catch(() => { });
|
|
61
|
+
}
|
|
62
|
+
async function writeStuckOutboxEntry(opts) {
|
|
63
|
+
try {
|
|
64
|
+
const outboxPath = path.join(os.homedir(), '.workrail', 'outbox.jsonl');
|
|
65
|
+
await fs.mkdir(path.dirname(outboxPath), { recursive: true });
|
|
66
|
+
const entry = JSON.stringify({
|
|
67
|
+
id: (0, node_crypto_1.randomUUID)(),
|
|
68
|
+
kind: 'stuck',
|
|
69
|
+
message: `Session stuck (${opts.reason}): workflowId=${opts.workflowId}` +
|
|
70
|
+
(opts.issueSummaries && opts.issueSummaries.length > 0
|
|
71
|
+
? ` -- issues: ${opts.issueSummaries.join('; ')}`
|
|
72
|
+
: ''),
|
|
73
|
+
timestamp: new Date().toISOString(),
|
|
74
|
+
workflowId: opts.workflowId,
|
|
75
|
+
reason: opts.reason,
|
|
76
|
+
...(opts.issueSummaries && opts.issueSummaries.length > 0
|
|
77
|
+
? { issueSummaries: opts.issueSummaries }
|
|
78
|
+
: {}),
|
|
79
|
+
});
|
|
80
|
+
await fs.appendFile(outboxPath, entry + '\n');
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
console.warn(`[WorkflowRunner] Could not write stuck outbox entry: ` +
|
|
84
|
+
`${err instanceof Error ? err.message : String(err)}`);
|
|
85
|
+
}
|
|
86
|
+
}
|