@exaudeus/workrail 3.31.1 → 3.33.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/cli/commands/index.d.ts +1 -0
- package/dist/cli/commands/index.js +3 -1
- package/dist/cli/commands/worktrain-await.js +11 -9
- package/dist/cli/commands/worktrain-daemon-install.d.ts +35 -0
- package/dist/cli/commands/worktrain-daemon-install.js +291 -0
- package/dist/cli/commands/worktrain-daemon.d.ts +31 -0
- package/dist/cli/commands/worktrain-daemon.js +272 -0
- package/dist/cli/commands/worktrain-spawn.js +11 -9
- package/dist/cli-worktrain.js +329 -0
- package/dist/cli.js +4 -22
- package/dist/console/standalone-console.d.ts +28 -0
- package/dist/console/standalone-console.js +142 -0
- package/dist/{console/assets/index-6H9DeFxj.js → console-ui/assets/index-BuJFLLfY.js} +1 -1
- package/dist/{console → console-ui}/index.html +1 -1
- package/dist/daemon/agent-loop.d.ts +26 -0
- package/dist/daemon/agent-loop.js +53 -2
- package/dist/daemon/daemon-events.d.ts +103 -0
- package/dist/daemon/daemon-events.js +56 -0
- package/dist/daemon/workflow-runner.d.ts +6 -3
- package/dist/daemon/workflow-runner.js +229 -33
- package/dist/infrastructure/session/HttpServer.js +133 -34
- package/dist/manifest.json +134 -70
- package/dist/mcp/output-schemas.d.ts +30 -30
- package/dist/mcp/transports/bridge-events.d.ts +4 -0
- package/dist/mcp/transports/fatal-exit.js +4 -0
- package/dist/mcp/transports/http-entry.js +2 -0
- package/dist/mcp/transports/stdio-entry.js +26 -6
- package/dist/mcp/v2/tools.d.ts +4 -4
- package/dist/trigger/adapters/github-poller.d.ts +44 -0
- package/dist/trigger/adapters/github-poller.js +190 -0
- package/dist/trigger/adapters/gitlab-poller.d.ts +27 -0
- package/dist/trigger/adapters/gitlab-poller.js +81 -0
- package/dist/trigger/delivery-client.d.ts +2 -1
- package/dist/trigger/delivery-client.js +4 -1
- package/dist/trigger/index.d.ts +4 -1
- package/dist/trigger/index.js +5 -1
- package/dist/trigger/polled-event-store.d.ts +22 -0
- package/dist/trigger/polled-event-store.js +173 -0
- package/dist/trigger/polling-scheduler.d.ts +20 -0
- package/dist/trigger/polling-scheduler.js +249 -0
- package/dist/trigger/trigger-listener.d.ts +5 -0
- package/dist/trigger/trigger-listener.js +53 -4
- package/dist/trigger/trigger-router.d.ts +4 -2
- package/dist/trigger/trigger-router.js +7 -4
- package/dist/trigger/trigger-store.js +114 -33
- package/dist/trigger/types.d.ts +17 -1
- package/dist/v2/durable-core/schemas/export-bundle/index.d.ts +224 -224
- package/dist/v2/durable-core/schemas/session/events.d.ts +42 -42
- package/dist/v2/durable-core/schemas/session/manifest.d.ts +6 -6
- package/dist/v2/durable-core/schemas/session/validation-event.d.ts +2 -2
- package/dist/v2/durable-core/tokens/payloads.d.ts +52 -52
- package/dist/v2/usecases/console-routes.js +3 -3
- package/dist/v2/usecases/console-service.js +133 -9
- package/dist/v2/usecases/console-types.d.ts +7 -0
- package/docs/design/daemon-conversation-logging-plan.md +98 -0
- package/docs/design/daemon-conversation-logging-review.md +55 -0
- package/docs/design/daemon-conversation-logging.md +129 -0
- package/docs/design/github-polling-adapter-design-candidates.md +226 -0
- package/docs/design/github-polling-adapter-design-review-findings.md +131 -0
- package/docs/design/github-polling-adapter-implementation-plan.md +284 -0
- package/docs/design/implementation_plan.md +192 -0
- package/docs/design/workflow-id-validation-at-startup.md +146 -0
- package/docs/design/workflow-id-validation-design-review.md +87 -0
- package/docs/design/workflow-id-validation-implementation-plan.md +185 -0
- package/docs/design/worktrain-system-prompt-report-issue-candidates.md +135 -0
- package/docs/design/worktrain-system-prompt-report-issue-design-review.md +73 -0
- package/docs/ideas/backlog.md +465 -0
- package/package.json +1 -1
- package/workflows/architecture-scalability-audit.json +1 -1
- package/workflows/bug-investigation.agentic.v2.json +3 -3
- package/workflows/coding-task-workflow-agentic.json +32 -32
- package/workflows/coding-task-workflow-agentic.lean.v2.json +1 -1
- package/workflows/coding-task-workflow-agentic.v2.json +7 -7
- package/workflows/mr-review-workflow.agentic.v2.json +21 -12
- package/workflows/personal-learning-materials-creation-branched.json +2 -2
- package/workflows/production-readiness-audit.json +1 -1
- package/workflows/relocation-workflow-us.json +2 -2
- package/workflows/ui-ux-design-workflow.json +14 -14
- package/workflows/workflow-for-workflows.json +3 -3
- package/workflows/workflow-for-workflows.v2.json +2 -2
- package/workflows/wr.discovery.json +1 -1
- /package/dist/{console → console-ui}/assets/index-8dh0Psu-.css +0 -0
|
@@ -43,7 +43,7 @@ class AgentLoop {
|
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
async _runLoop() {
|
|
46
|
-
const { client, modelId, systemPrompt, tools, maxTokens = 8192 } = this._options;
|
|
46
|
+
const { client, modelId, systemPrompt, tools, maxTokens = 8192, callbacks } = this._options;
|
|
47
47
|
while (true) {
|
|
48
48
|
if (this._aborted || this._abortController.signal.aborted) {
|
|
49
49
|
this._appendErrorMessage('aborted');
|
|
@@ -56,6 +56,10 @@ class AgentLoop {
|
|
|
56
56
|
description: t.description,
|
|
57
57
|
input_schema: t.inputSchema,
|
|
58
58
|
}));
|
|
59
|
+
try {
|
|
60
|
+
callbacks?.onLlmTurnStarted?.({ messageCount: apiMessages.length });
|
|
61
|
+
}
|
|
62
|
+
catch { }
|
|
59
63
|
let response;
|
|
60
64
|
try {
|
|
61
65
|
response = await client.messages.create({
|
|
@@ -74,6 +78,20 @@ class AgentLoop {
|
|
|
74
78
|
await this._emitEvent({ type: 'agent_end' });
|
|
75
79
|
return;
|
|
76
80
|
}
|
|
81
|
+
{
|
|
82
|
+
const toolNamesRequested = response.content
|
|
83
|
+
.filter((block) => block.type === 'tool_use')
|
|
84
|
+
.map((block) => block.name);
|
|
85
|
+
try {
|
|
86
|
+
callbacks?.onLlmTurnCompleted?.({
|
|
87
|
+
stopReason: response.stop_reason ?? 'unknown',
|
|
88
|
+
outputTokens: response.usage.output_tokens,
|
|
89
|
+
inputTokens: response.usage.input_tokens,
|
|
90
|
+
toolNamesRequested,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
catch { }
|
|
94
|
+
}
|
|
77
95
|
const stopReason = this._mapStopReason(response.stop_reason);
|
|
78
96
|
const assistantMsg = {
|
|
79
97
|
role: 'assistant',
|
|
@@ -116,6 +134,7 @@ class AgentLoop {
|
|
|
116
134
|
}
|
|
117
135
|
}
|
|
118
136
|
async _executeTools(toolUseBlocks) {
|
|
137
|
+
const { callbacks } = this._options;
|
|
119
138
|
const results = [];
|
|
120
139
|
for (const block of toolUseBlocks) {
|
|
121
140
|
if (this._abortController.signal.aborted) {
|
|
@@ -141,7 +160,39 @@ class AgentLoop {
|
|
|
141
160
|
continue;
|
|
142
161
|
}
|
|
143
162
|
const params = (block.input ?? {});
|
|
144
|
-
const
|
|
163
|
+
const argsSummary = JSON.stringify(params).slice(0, 200);
|
|
164
|
+
try {
|
|
165
|
+
callbacks?.onToolCallStarted?.({ toolName: block.name, argsSummary });
|
|
166
|
+
}
|
|
167
|
+
catch { }
|
|
168
|
+
const toolStartMs = Date.now();
|
|
169
|
+
let result;
|
|
170
|
+
try {
|
|
171
|
+
result = await tool.execute(block.id, params);
|
|
172
|
+
}
|
|
173
|
+
catch (err) {
|
|
174
|
+
const durationMs = Date.now() - toolStartMs;
|
|
175
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
176
|
+
try {
|
|
177
|
+
callbacks?.onToolCallFailed?.({ toolName: block.name, durationMs, errorMessage: message.slice(0, 200) });
|
|
178
|
+
}
|
|
179
|
+
catch { }
|
|
180
|
+
results.push({
|
|
181
|
+
toolCallId: block.id,
|
|
182
|
+
toolName: block.name,
|
|
183
|
+
result: { content: [{ type: 'text', text: `Tool execution failed: ${message}` }], details: null },
|
|
184
|
+
isError: true,
|
|
185
|
+
});
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
{
|
|
189
|
+
const durationMs = Date.now() - toolStartMs;
|
|
190
|
+
const resultSummary = (result.content[0]?.text ?? '(no output)').slice(0, 200);
|
|
191
|
+
try {
|
|
192
|
+
callbacks?.onToolCallCompleted?.({ toolName: block.name, durationMs, resultSummary });
|
|
193
|
+
}
|
|
194
|
+
catch { }
|
|
195
|
+
}
|
|
145
196
|
results.push({
|
|
146
197
|
toolCallId: block.id,
|
|
147
198
|
toolName: block.name,
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
export interface DaemonStartedEvent {
|
|
2
|
+
readonly kind: 'daemon_started';
|
|
3
|
+
readonly port: number;
|
|
4
|
+
readonly workspacePath: string;
|
|
5
|
+
}
|
|
6
|
+
export interface TriggerFiredEvent {
|
|
7
|
+
readonly kind: 'trigger_fired';
|
|
8
|
+
readonly triggerId: string;
|
|
9
|
+
readonly workflowId: string;
|
|
10
|
+
}
|
|
11
|
+
export interface SessionQueuedEvent {
|
|
12
|
+
readonly kind: 'session_queued';
|
|
13
|
+
readonly triggerId: string;
|
|
14
|
+
readonly workflowId: string;
|
|
15
|
+
}
|
|
16
|
+
export interface SessionStartedEvent {
|
|
17
|
+
readonly kind: 'session_started';
|
|
18
|
+
readonly sessionId: string;
|
|
19
|
+
readonly workflowId: string;
|
|
20
|
+
readonly workspacePath: string;
|
|
21
|
+
readonly workrailSessionId?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface ToolCalledEvent {
|
|
24
|
+
readonly kind: 'tool_called';
|
|
25
|
+
readonly sessionId: string;
|
|
26
|
+
readonly toolName: string;
|
|
27
|
+
readonly summary?: string;
|
|
28
|
+
readonly workrailSessionId?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface ToolErrorEvent {
|
|
31
|
+
readonly kind: 'tool_error';
|
|
32
|
+
readonly sessionId: string;
|
|
33
|
+
readonly toolName: string;
|
|
34
|
+
readonly error: string;
|
|
35
|
+
readonly workrailSessionId?: string;
|
|
36
|
+
}
|
|
37
|
+
export interface StepAdvancedEvent {
|
|
38
|
+
readonly kind: 'step_advanced';
|
|
39
|
+
readonly sessionId: string;
|
|
40
|
+
readonly workrailSessionId?: string;
|
|
41
|
+
}
|
|
42
|
+
export interface SessionCompletedEvent {
|
|
43
|
+
readonly kind: 'session_completed';
|
|
44
|
+
readonly sessionId: string;
|
|
45
|
+
readonly workflowId: string;
|
|
46
|
+
readonly outcome: 'success' | 'error' | 'timeout';
|
|
47
|
+
readonly detail?: string;
|
|
48
|
+
readonly workrailSessionId?: string;
|
|
49
|
+
}
|
|
50
|
+
export interface DeliveryAttemptedEvent {
|
|
51
|
+
readonly kind: 'delivery_attempted';
|
|
52
|
+
readonly callbackUrl: string;
|
|
53
|
+
readonly outcome: 'success' | 'http_error' | 'network_error';
|
|
54
|
+
readonly statusCode?: number;
|
|
55
|
+
}
|
|
56
|
+
export interface IssueReportedEvent {
|
|
57
|
+
readonly kind: 'issue_reported';
|
|
58
|
+
readonly sessionId: string;
|
|
59
|
+
readonly issueKind: 'tool_failure' | 'blocked' | 'unexpected_behavior' | 'needs_human' | 'self_correction';
|
|
60
|
+
readonly severity: 'info' | 'warn' | 'error' | 'fatal';
|
|
61
|
+
readonly summary: string;
|
|
62
|
+
readonly continueToken?: string;
|
|
63
|
+
}
|
|
64
|
+
export interface LlmTurnStartedEvent {
|
|
65
|
+
readonly kind: 'llm_turn_started';
|
|
66
|
+
readonly sessionId: string;
|
|
67
|
+
readonly messageCount: number;
|
|
68
|
+
}
|
|
69
|
+
export interface LlmTurnCompletedEvent {
|
|
70
|
+
readonly kind: 'llm_turn_completed';
|
|
71
|
+
readonly sessionId: string;
|
|
72
|
+
readonly stopReason: string;
|
|
73
|
+
readonly outputTokens: number;
|
|
74
|
+
readonly inputTokens: number;
|
|
75
|
+
readonly toolNamesRequested: readonly string[];
|
|
76
|
+
}
|
|
77
|
+
export interface ToolCallStartedEvent {
|
|
78
|
+
readonly kind: 'tool_call_started';
|
|
79
|
+
readonly sessionId: string;
|
|
80
|
+
readonly toolName: string;
|
|
81
|
+
readonly argsSummary: string;
|
|
82
|
+
}
|
|
83
|
+
export interface ToolCallCompletedEvent {
|
|
84
|
+
readonly kind: 'tool_call_completed';
|
|
85
|
+
readonly sessionId: string;
|
|
86
|
+
readonly toolName: string;
|
|
87
|
+
readonly durationMs: number;
|
|
88
|
+
readonly resultSummary: string;
|
|
89
|
+
}
|
|
90
|
+
export interface ToolCallFailedEvent {
|
|
91
|
+
readonly kind: 'tool_call_failed';
|
|
92
|
+
readonly sessionId: string;
|
|
93
|
+
readonly toolName: string;
|
|
94
|
+
readonly durationMs: number;
|
|
95
|
+
readonly errorMessage: string;
|
|
96
|
+
}
|
|
97
|
+
export type DaemonEvent = DaemonStartedEvent | TriggerFiredEvent | SessionQueuedEvent | SessionStartedEvent | ToolCalledEvent | ToolErrorEvent | StepAdvancedEvent | SessionCompletedEvent | DeliveryAttemptedEvent | IssueReportedEvent | LlmTurnStartedEvent | LlmTurnCompletedEvent | ToolCallStartedEvent | ToolCallCompletedEvent | ToolCallFailedEvent;
|
|
98
|
+
export declare class DaemonEventEmitter {
|
|
99
|
+
private readonly _dir;
|
|
100
|
+
constructor(dirOverride?: string);
|
|
101
|
+
emit(event: DaemonEvent): void;
|
|
102
|
+
private _append;
|
|
103
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
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.DaemonEventEmitter = void 0;
|
|
37
|
+
const fs = __importStar(require("node:fs/promises"));
|
|
38
|
+
const path = __importStar(require("node:path"));
|
|
39
|
+
const os = __importStar(require("node:os"));
|
|
40
|
+
class DaemonEventEmitter {
|
|
41
|
+
constructor(dirOverride) {
|
|
42
|
+
this._dir = dirOverride ?? path.join(os.homedir(), '.workrail', 'events', 'daemon');
|
|
43
|
+
}
|
|
44
|
+
emit(event) {
|
|
45
|
+
void this._append(event).catch(() => {
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
async _append(event) {
|
|
49
|
+
const date = new Date().toISOString().slice(0, 10);
|
|
50
|
+
const filePath = path.join(this._dir, `${date}.jsonl`);
|
|
51
|
+
await fs.mkdir(this._dir, { recursive: true });
|
|
52
|
+
const line = JSON.stringify({ ...event, ts: Date.now() }) + '\n';
|
|
53
|
+
await fs.appendFile(filePath, line, 'utf8');
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
exports.DaemonEventEmitter = DaemonEventEmitter;
|
|
@@ -4,6 +4,7 @@ import type { V2ToolContext } from '../mcp/types.js';
|
|
|
4
4
|
import { executeContinueWorkflow } from '../mcp/handlers/v2-execution/index.js';
|
|
5
5
|
import type { DaemonRegistry } from '../v2/infra/in-memory/daemon-registry/index.js';
|
|
6
6
|
import type { V2StartWorkflowOutputSchema } from '../mcp/output-schemas.js';
|
|
7
|
+
import type { DaemonEventEmitter } from './daemon-events.js';
|
|
7
8
|
export declare const DAEMON_SESSIONS_DIR: string;
|
|
8
9
|
export { DAEMON_SOUL_DEFAULT, DAEMON_SOUL_TEMPLATE } from './soul-template.js';
|
|
9
10
|
export interface WorkflowTrigger {
|
|
@@ -31,6 +32,7 @@ export interface WorkflowRunError {
|
|
|
31
32
|
readonly workflowId: string;
|
|
32
33
|
readonly message: string;
|
|
33
34
|
readonly stopReason: string;
|
|
35
|
+
readonly lastStepNotes?: string;
|
|
34
36
|
}
|
|
35
37
|
export interface WorkflowRunTimeout {
|
|
36
38
|
readonly _tag: 'timeout';
|
|
@@ -58,8 +60,9 @@ export declare function readDaemonSessionState(sessionId: string): Promise<{
|
|
|
58
60
|
} | null>;
|
|
59
61
|
export declare function readAllDaemonSessions(sessionsDir?: string): Promise<OrphanedSession[]>;
|
|
60
62
|
export declare function runStartupRecovery(sessionsDir?: string): Promise<void>;
|
|
61
|
-
export declare function makeContinueWorkflowTool(sessionId: string, ctx: V2ToolContext, onAdvance: (nextStepText: string, continueToken: string) => void, onComplete: (notes: string | undefined) => void, schemas: Record<string, any>, _executeContinueWorkflowFn?: typeof executeContinueWorkflow): AgentTool;
|
|
62
|
-
export declare function makeBashTool(workspacePath: string, schemas: Record<string, any
|
|
63
|
+
export declare function makeContinueWorkflowTool(sessionId: string, ctx: V2ToolContext, onAdvance: (nextStepText: string, continueToken: string) => void, onComplete: (notes: string | undefined) => void, schemas: Record<string, any>, _executeContinueWorkflowFn?: typeof executeContinueWorkflow, emitter?: DaemonEventEmitter, workrailSessionId?: string | null): AgentTool;
|
|
64
|
+
export declare function makeBashTool(workspacePath: string, schemas: Record<string, any>, sessionId?: string, emitter?: DaemonEventEmitter, workrailSessionId?: string | null): AgentTool;
|
|
65
|
+
export declare function makeReportIssueTool(sessionId: string, emitter?: DaemonEventEmitter, issuesDirOverride?: string): AgentTool;
|
|
63
66
|
export declare function buildSessionRecap(notes: readonly string[]): string;
|
|
64
67
|
export declare function buildSystemPrompt(trigger: WorkflowTrigger, sessionState: string, soulContent: string, workspaceContext: string | null): string;
|
|
65
|
-
export declare function runWorkflow(trigger: WorkflowTrigger, ctx: V2ToolContext, apiKey: string, daemonRegistry?: DaemonRegistry): Promise<WorkflowRunResult>;
|
|
68
|
+
export declare function runWorkflow(trigger: WorkflowTrigger, ctx: V2ToolContext, apiKey: string, daemonRegistry?: DaemonRegistry, emitter?: DaemonEventEmitter): Promise<WorkflowRunResult>;
|