@exaudeus/workrail 3.7.0 → 3.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/dist/manifest.json +35 -35
- package/dist/mcp/handler-factory.js +1 -1
- package/dist/mcp/handlers/v2-resume.js +5 -0
- package/dist/mcp/output-schemas.d.ts +24 -9
- package/dist/mcp/output-schemas.js +8 -1
- package/dist/mcp/server.js +1 -0
- package/dist/mcp/v2/tools.d.ts +6 -0
- package/dist/mcp/v2/tools.js +5 -0
- package/dist/mcp/v2-response-formatter.d.ts +1 -0
- package/dist/mcp/v2-response-formatter.js +148 -0
- package/dist/mcp/workflow-protocol-contracts.js +19 -19
- package/dist/v2/durable-core/schemas/export-bundle/index.d.ts +10 -10
- package/dist/v2/durable-core/schemas/session/manifest.d.ts +2 -2
- package/dist/v2/durable-core/tokens/payloads.d.ts +24 -24
- package/dist/v2/infra/local/session-summary-provider/index.d.ts +2 -0
- package/dist/v2/infra/local/session-summary-provider/index.js +54 -17
- package/dist/v2/projections/resume-ranking.d.ts +21 -2
- package/dist/v2/projections/resume-ranking.js +66 -6
- package/dist/v2/usecases/enumerate-sessions.d.ts +5 -1
- package/dist/v2/usecases/enumerate-sessions.js +1 -1
- package/package.json +1 -1
- package/workflows/cross-platform-code-conversion.v2.json +278 -34
|
@@ -2183,8 +2183,8 @@ export declare const SessionContentsV1Schema: z.ZodObject<{
|
|
|
2183
2183
|
bytes: z.ZodNumber;
|
|
2184
2184
|
}, "strip", z.ZodTypeAny, {
|
|
2185
2185
|
kind: "segment_closed";
|
|
2186
|
-
sha256: string;
|
|
2187
2186
|
sessionId: string;
|
|
2187
|
+
sha256: string;
|
|
2188
2188
|
v: 1;
|
|
2189
2189
|
manifestIndex: number;
|
|
2190
2190
|
firstEventIndex: number;
|
|
@@ -2193,8 +2193,8 @@ export declare const SessionContentsV1Schema: z.ZodObject<{
|
|
|
2193
2193
|
bytes: number;
|
|
2194
2194
|
}, {
|
|
2195
2195
|
kind: "segment_closed";
|
|
2196
|
-
sha256: string;
|
|
2197
2196
|
sessionId: string;
|
|
2197
|
+
sha256: string;
|
|
2198
2198
|
v: 1;
|
|
2199
2199
|
manifestIndex: number;
|
|
2200
2200
|
firstEventIndex: number;
|
|
@@ -4601,8 +4601,8 @@ export declare const SessionContentsV1Schema: z.ZodObject<{
|
|
|
4601
4601
|
})[];
|
|
4602
4602
|
manifest: ({
|
|
4603
4603
|
kind: "segment_closed";
|
|
4604
|
-
sha256: string;
|
|
4605
4604
|
sessionId: string;
|
|
4605
|
+
sha256: string;
|
|
4606
4606
|
v: 1;
|
|
4607
4607
|
manifestIndex: number;
|
|
4608
4608
|
firstEventIndex: number;
|
|
@@ -5113,8 +5113,8 @@ export declare const SessionContentsV1Schema: z.ZodObject<{
|
|
|
5113
5113
|
})[];
|
|
5114
5114
|
manifest: ({
|
|
5115
5115
|
kind: "segment_closed";
|
|
5116
|
-
sha256: string;
|
|
5117
5116
|
sessionId: string;
|
|
5117
|
+
sha256: string;
|
|
5118
5118
|
v: 1;
|
|
5119
5119
|
manifestIndex: number;
|
|
5120
5120
|
firstEventIndex: number;
|
|
@@ -7305,8 +7305,8 @@ export declare const ExportBundleV1Schema: z.ZodObject<{
|
|
|
7305
7305
|
bytes: z.ZodNumber;
|
|
7306
7306
|
}, "strip", z.ZodTypeAny, {
|
|
7307
7307
|
kind: "segment_closed";
|
|
7308
|
-
sha256: string;
|
|
7309
7308
|
sessionId: string;
|
|
7309
|
+
sha256: string;
|
|
7310
7310
|
v: 1;
|
|
7311
7311
|
manifestIndex: number;
|
|
7312
7312
|
firstEventIndex: number;
|
|
@@ -7315,8 +7315,8 @@ export declare const ExportBundleV1Schema: z.ZodObject<{
|
|
|
7315
7315
|
bytes: number;
|
|
7316
7316
|
}, {
|
|
7317
7317
|
kind: "segment_closed";
|
|
7318
|
-
sha256: string;
|
|
7319
7318
|
sessionId: string;
|
|
7319
|
+
sha256: string;
|
|
7320
7320
|
v: 1;
|
|
7321
7321
|
manifestIndex: number;
|
|
7322
7322
|
firstEventIndex: number;
|
|
@@ -9723,8 +9723,8 @@ export declare const ExportBundleV1Schema: z.ZodObject<{
|
|
|
9723
9723
|
})[];
|
|
9724
9724
|
manifest: ({
|
|
9725
9725
|
kind: "segment_closed";
|
|
9726
|
-
sha256: string;
|
|
9727
9726
|
sessionId: string;
|
|
9727
|
+
sha256: string;
|
|
9728
9728
|
v: 1;
|
|
9729
9729
|
manifestIndex: number;
|
|
9730
9730
|
firstEventIndex: number;
|
|
@@ -10235,8 +10235,8 @@ export declare const ExportBundleV1Schema: z.ZodObject<{
|
|
|
10235
10235
|
})[];
|
|
10236
10236
|
manifest: ({
|
|
10237
10237
|
kind: "segment_closed";
|
|
10238
|
-
sha256: string;
|
|
10239
10238
|
sessionId: string;
|
|
10239
|
+
sha256: string;
|
|
10240
10240
|
v: 1;
|
|
10241
10241
|
manifestIndex: number;
|
|
10242
10242
|
firstEventIndex: number;
|
|
@@ -10776,8 +10776,8 @@ export declare const ExportBundleV1Schema: z.ZodObject<{
|
|
|
10776
10776
|
})[];
|
|
10777
10777
|
manifest: ({
|
|
10778
10778
|
kind: "segment_closed";
|
|
10779
|
-
sha256: string;
|
|
10780
10779
|
sessionId: string;
|
|
10780
|
+
sha256: string;
|
|
10781
10781
|
v: 1;
|
|
10782
10782
|
manifestIndex: number;
|
|
10783
10783
|
firstEventIndex: number;
|
|
@@ -11305,8 +11305,8 @@ export declare const ExportBundleV1Schema: z.ZodObject<{
|
|
|
11305
11305
|
})[];
|
|
11306
11306
|
manifest: ({
|
|
11307
11307
|
kind: "segment_closed";
|
|
11308
|
-
sha256: string;
|
|
11309
11308
|
sessionId: string;
|
|
11309
|
+
sha256: string;
|
|
11310
11310
|
v: 1;
|
|
11311
11311
|
manifestIndex: number;
|
|
11312
11312
|
firstEventIndex: number;
|
|
@@ -11,8 +11,8 @@ export declare const ManifestRecordV1Schema: z.ZodDiscriminatedUnion<"kind", [z.
|
|
|
11
11
|
bytes: z.ZodNumber;
|
|
12
12
|
}, "strip", z.ZodTypeAny, {
|
|
13
13
|
kind: "segment_closed";
|
|
14
|
-
sha256: string;
|
|
15
14
|
sessionId: string;
|
|
15
|
+
sha256: string;
|
|
16
16
|
v: 1;
|
|
17
17
|
manifestIndex: number;
|
|
18
18
|
firstEventIndex: number;
|
|
@@ -21,8 +21,8 @@ export declare const ManifestRecordV1Schema: z.ZodDiscriminatedUnion<"kind", [z.
|
|
|
21
21
|
bytes: number;
|
|
22
22
|
}, {
|
|
23
23
|
kind: "segment_closed";
|
|
24
|
-
sha256: string;
|
|
25
24
|
sessionId: string;
|
|
25
|
+
sha256: string;
|
|
26
26
|
v: 1;
|
|
27
27
|
manifestIndex: number;
|
|
28
28
|
firstEventIndex: number;
|
|
@@ -14,13 +14,13 @@ export declare const StateTokenPayloadV1Schema: z.ZodObject<{
|
|
|
14
14
|
nodeId: z.ZodEffects<z.ZodString, NodeId, string>;
|
|
15
15
|
workflowHashRef: z.ZodEffects<z.ZodString, WorkflowHashRef, string>;
|
|
16
16
|
}, "strip", z.ZodTypeAny, {
|
|
17
|
+
runId: string & {
|
|
18
|
+
readonly __brand: "v2.RunId";
|
|
19
|
+
};
|
|
17
20
|
sessionId: string & {
|
|
18
21
|
readonly __brand: "v2.SessionId";
|
|
19
22
|
};
|
|
20
23
|
tokenKind: "state";
|
|
21
|
-
runId: string & {
|
|
22
|
-
readonly __brand: "v2.RunId";
|
|
23
|
-
};
|
|
24
24
|
nodeId: string & {
|
|
25
25
|
readonly __brand: "v2.NodeId";
|
|
26
26
|
};
|
|
@@ -29,9 +29,9 @@ export declare const StateTokenPayloadV1Schema: z.ZodObject<{
|
|
|
29
29
|
};
|
|
30
30
|
tokenVersion: 1;
|
|
31
31
|
}, {
|
|
32
|
+
runId: string;
|
|
32
33
|
sessionId: string;
|
|
33
34
|
tokenKind: "state";
|
|
34
|
-
runId: string;
|
|
35
35
|
nodeId: string;
|
|
36
36
|
workflowHashRef: string;
|
|
37
37
|
tokenVersion: 1;
|
|
@@ -52,13 +52,13 @@ export declare const AckTokenPayloadV1Schema: z.ZodObject<{
|
|
|
52
52
|
nodeId: z.ZodEffects<z.ZodString, NodeId, string>;
|
|
53
53
|
attemptId: z.ZodEffects<z.ZodString, AttemptId, string>;
|
|
54
54
|
}, "strip", z.ZodTypeAny, {
|
|
55
|
+
runId: string & {
|
|
56
|
+
readonly __brand: "v2.RunId";
|
|
57
|
+
};
|
|
55
58
|
sessionId: string & {
|
|
56
59
|
readonly __brand: "v2.SessionId";
|
|
57
60
|
};
|
|
58
61
|
tokenKind: "ack";
|
|
59
|
-
runId: string & {
|
|
60
|
-
readonly __brand: "v2.RunId";
|
|
61
|
-
};
|
|
62
62
|
nodeId: string & {
|
|
63
63
|
readonly __brand: "v2.NodeId";
|
|
64
64
|
};
|
|
@@ -67,9 +67,9 @@ export declare const AckTokenPayloadV1Schema: z.ZodObject<{
|
|
|
67
67
|
};
|
|
68
68
|
tokenVersion: 1;
|
|
69
69
|
}, {
|
|
70
|
+
runId: string;
|
|
70
71
|
sessionId: string;
|
|
71
72
|
tokenKind: "ack";
|
|
72
|
-
runId: string;
|
|
73
73
|
nodeId: string;
|
|
74
74
|
attemptId: string;
|
|
75
75
|
tokenVersion: 1;
|
|
@@ -90,13 +90,13 @@ export declare const CheckpointTokenPayloadV1Schema: z.ZodObject<{
|
|
|
90
90
|
nodeId: z.ZodEffects<z.ZodString, NodeId, string>;
|
|
91
91
|
attemptId: z.ZodEffects<z.ZodString, AttemptId, string>;
|
|
92
92
|
}, "strip", z.ZodTypeAny, {
|
|
93
|
+
runId: string & {
|
|
94
|
+
readonly __brand: "v2.RunId";
|
|
95
|
+
};
|
|
93
96
|
sessionId: string & {
|
|
94
97
|
readonly __brand: "v2.SessionId";
|
|
95
98
|
};
|
|
96
99
|
tokenKind: "checkpoint";
|
|
97
|
-
runId: string & {
|
|
98
|
-
readonly __brand: "v2.RunId";
|
|
99
|
-
};
|
|
100
100
|
nodeId: string & {
|
|
101
101
|
readonly __brand: "v2.NodeId";
|
|
102
102
|
};
|
|
@@ -105,9 +105,9 @@ export declare const CheckpointTokenPayloadV1Schema: z.ZodObject<{
|
|
|
105
105
|
};
|
|
106
106
|
tokenVersion: 1;
|
|
107
107
|
}, {
|
|
108
|
+
runId: string;
|
|
108
109
|
sessionId: string;
|
|
109
110
|
tokenKind: "checkpoint";
|
|
110
|
-
runId: string;
|
|
111
111
|
nodeId: string;
|
|
112
112
|
attemptId: string;
|
|
113
113
|
tokenVersion: 1;
|
|
@@ -128,13 +128,13 @@ export declare const TokenPayloadV1Schema: z.ZodDiscriminatedUnion<"tokenKind",
|
|
|
128
128
|
nodeId: z.ZodEffects<z.ZodString, NodeId, string>;
|
|
129
129
|
workflowHashRef: z.ZodEffects<z.ZodString, WorkflowHashRef, string>;
|
|
130
130
|
}, "strip", z.ZodTypeAny, {
|
|
131
|
+
runId: string & {
|
|
132
|
+
readonly __brand: "v2.RunId";
|
|
133
|
+
};
|
|
131
134
|
sessionId: string & {
|
|
132
135
|
readonly __brand: "v2.SessionId";
|
|
133
136
|
};
|
|
134
137
|
tokenKind: "state";
|
|
135
|
-
runId: string & {
|
|
136
|
-
readonly __brand: "v2.RunId";
|
|
137
|
-
};
|
|
138
138
|
nodeId: string & {
|
|
139
139
|
readonly __brand: "v2.NodeId";
|
|
140
140
|
};
|
|
@@ -143,9 +143,9 @@ export declare const TokenPayloadV1Schema: z.ZodDiscriminatedUnion<"tokenKind",
|
|
|
143
143
|
};
|
|
144
144
|
tokenVersion: 1;
|
|
145
145
|
}, {
|
|
146
|
+
runId: string;
|
|
146
147
|
sessionId: string;
|
|
147
148
|
tokenKind: "state";
|
|
148
|
-
runId: string;
|
|
149
149
|
nodeId: string;
|
|
150
150
|
workflowHashRef: string;
|
|
151
151
|
tokenVersion: 1;
|
|
@@ -157,13 +157,13 @@ export declare const TokenPayloadV1Schema: z.ZodDiscriminatedUnion<"tokenKind",
|
|
|
157
157
|
nodeId: z.ZodEffects<z.ZodString, NodeId, string>;
|
|
158
158
|
attemptId: z.ZodEffects<z.ZodString, AttemptId, string>;
|
|
159
159
|
}, "strip", z.ZodTypeAny, {
|
|
160
|
+
runId: string & {
|
|
161
|
+
readonly __brand: "v2.RunId";
|
|
162
|
+
};
|
|
160
163
|
sessionId: string & {
|
|
161
164
|
readonly __brand: "v2.SessionId";
|
|
162
165
|
};
|
|
163
166
|
tokenKind: "ack";
|
|
164
|
-
runId: string & {
|
|
165
|
-
readonly __brand: "v2.RunId";
|
|
166
|
-
};
|
|
167
167
|
nodeId: string & {
|
|
168
168
|
readonly __brand: "v2.NodeId";
|
|
169
169
|
};
|
|
@@ -172,9 +172,9 @@ export declare const TokenPayloadV1Schema: z.ZodDiscriminatedUnion<"tokenKind",
|
|
|
172
172
|
};
|
|
173
173
|
tokenVersion: 1;
|
|
174
174
|
}, {
|
|
175
|
+
runId: string;
|
|
175
176
|
sessionId: string;
|
|
176
177
|
tokenKind: "ack";
|
|
177
|
-
runId: string;
|
|
178
178
|
nodeId: string;
|
|
179
179
|
attemptId: string;
|
|
180
180
|
tokenVersion: 1;
|
|
@@ -186,13 +186,13 @@ export declare const TokenPayloadV1Schema: z.ZodDiscriminatedUnion<"tokenKind",
|
|
|
186
186
|
nodeId: z.ZodEffects<z.ZodString, NodeId, string>;
|
|
187
187
|
attemptId: z.ZodEffects<z.ZodString, AttemptId, string>;
|
|
188
188
|
}, "strip", z.ZodTypeAny, {
|
|
189
|
+
runId: string & {
|
|
190
|
+
readonly __brand: "v2.RunId";
|
|
191
|
+
};
|
|
189
192
|
sessionId: string & {
|
|
190
193
|
readonly __brand: "v2.SessionId";
|
|
191
194
|
};
|
|
192
195
|
tokenKind: "checkpoint";
|
|
193
|
-
runId: string & {
|
|
194
|
-
readonly __brand: "v2.RunId";
|
|
195
|
-
};
|
|
196
196
|
nodeId: string & {
|
|
197
197
|
readonly __brand: "v2.NodeId";
|
|
198
198
|
};
|
|
@@ -201,9 +201,9 @@ export declare const TokenPayloadV1Schema: z.ZodDiscriminatedUnion<"tokenKind",
|
|
|
201
201
|
};
|
|
202
202
|
tokenVersion: 1;
|
|
203
203
|
}, {
|
|
204
|
+
runId: string;
|
|
204
205
|
sessionId: string;
|
|
205
206
|
tokenKind: "checkpoint";
|
|
206
|
-
runId: string;
|
|
207
207
|
nodeId: string;
|
|
208
208
|
attemptId: string;
|
|
209
209
|
tokenVersion: 1;
|
|
@@ -2,12 +2,14 @@ import type { ResultAsync } from 'neverthrow';
|
|
|
2
2
|
import type { DirectoryListingPortV2 } from '../../../ports/directory-listing.port.js';
|
|
3
3
|
import type { DataDirPortV2 } from '../../../ports/data-dir.port.js';
|
|
4
4
|
import type { SessionEventLogReadonlyStorePortV2 } from '../../../ports/session-event-log-store.port.js';
|
|
5
|
+
import type { SnapshotStorePortV2 } from '../../../ports/snapshot-store.port.js';
|
|
5
6
|
import type { SessionSummaryProviderPortV2, SessionSummaryError } from '../../../ports/session-summary-provider.port.js';
|
|
6
7
|
import type { HealthySessionSummary } from '../../../projections/resume-ranking.js';
|
|
7
8
|
export interface LocalSessionSummaryProviderPorts {
|
|
8
9
|
readonly directoryListing: DirectoryListingPortV2;
|
|
9
10
|
readonly dataDir: DataDirPortV2;
|
|
10
11
|
readonly sessionStore: SessionEventLogReadonlyStorePortV2;
|
|
12
|
+
readonly snapshotStore?: SnapshotStorePortV2;
|
|
11
13
|
}
|
|
12
14
|
export declare class LocalSessionSummaryProviderV2 implements SessionSummaryProviderPortV2 {
|
|
13
15
|
private readonly ports;
|
|
@@ -7,9 +7,10 @@ const enumerate_sessions_js_1 = require("../../../usecases/enumerate-sessions.js
|
|
|
7
7
|
const session_health_js_1 = require("../../../projections/session-health.js");
|
|
8
8
|
const run_dag_js_1 = require("../../../projections/run-dag.js");
|
|
9
9
|
const node_outputs_js_1 = require("../../../projections/node-outputs.js");
|
|
10
|
+
const snapshot_state_js_1 = require("../../../durable-core/projections/snapshot-state.js");
|
|
10
11
|
const index_js_1 = require("../../../durable-core/ids/index.js");
|
|
11
12
|
const constants_js_1 = require("../../../durable-core/constants.js");
|
|
12
|
-
const MAX_SESSIONS_TO_SCAN =
|
|
13
|
+
const MAX_SESSIONS_TO_SCAN = 200;
|
|
13
14
|
const MAX_RECAP_ANCESTOR_DEPTH = 100;
|
|
14
15
|
const EMPTY_OBSERVATIONS = {
|
|
15
16
|
gitHeadSha: null,
|
|
@@ -29,20 +30,48 @@ class LocalSessionSummaryProviderV2 {
|
|
|
29
30
|
code: 'SESSION_SUMMARY_ENUMERATION_FAILED',
|
|
30
31
|
message: `Failed to enumerate sessions: ${fsErr.message}`,
|
|
31
32
|
}))
|
|
32
|
-
.andThen((
|
|
33
|
+
.andThen((entries) => collectHealthySummaries(entries.slice(0, MAX_SESSIONS_TO_SCAN), this.ports.sessionStore, this.ports.snapshotStore ?? null));
|
|
33
34
|
}
|
|
34
35
|
}
|
|
35
36
|
exports.LocalSessionSummaryProviderV2 = LocalSessionSummaryProviderV2;
|
|
36
|
-
function collectHealthySummaries(
|
|
37
|
-
return
|
|
37
|
+
function collectHealthySummaries(entries, sessionStore, snapshotStore) {
|
|
38
|
+
return entries.reduce((acc, entry) => acc.andThen((summaries) => loadSessionSummary(entry, sessionStore, snapshotStore).map((summary) => summary !== null ? [...summaries, summary] : summaries)), (0, neverthrow_1.okAsync)([]));
|
|
38
39
|
}
|
|
39
|
-
function loadSessionSummary(
|
|
40
|
+
function loadSessionSummary(entry, sessionStore, snapshotStore) {
|
|
40
41
|
return sessionStore
|
|
41
|
-
.load(sessionId)
|
|
42
|
-
.
|
|
42
|
+
.load(entry.sessionId)
|
|
43
|
+
.andThen((truth) => {
|
|
44
|
+
const projected = projectSessionSummary(entry.sessionId, truth, entry.mtimeMs);
|
|
45
|
+
if (!projected)
|
|
46
|
+
return (0, neverthrow_1.okAsync)(null);
|
|
47
|
+
if (!snapshotStore)
|
|
48
|
+
return (0, neverthrow_1.okAsync)(projected.summary);
|
|
49
|
+
const ref = safeSnapshotRef(projected.tipSnapshotRef);
|
|
50
|
+
if (!ref)
|
|
51
|
+
return (0, neverthrow_1.okAsync)(projected.summary);
|
|
52
|
+
return snapshotStore.getExecutionSnapshotV1(ref)
|
|
53
|
+
.map((snapshot) => {
|
|
54
|
+
if (!snapshot)
|
|
55
|
+
return projected.summary;
|
|
56
|
+
const engineState = snapshot.enginePayload.engineState;
|
|
57
|
+
const pending = (0, snapshot_state_js_1.derivePendingStep)(engineState);
|
|
58
|
+
const isComplete = (0, snapshot_state_js_1.deriveIsComplete)(engineState);
|
|
59
|
+
return {
|
|
60
|
+
...projected.summary,
|
|
61
|
+
pendingStepId: pending?.stepId ?? null,
|
|
62
|
+
isComplete,
|
|
63
|
+
};
|
|
64
|
+
})
|
|
65
|
+
.orElse(() => (0, neverthrow_1.okAsync)(projected.summary));
|
|
66
|
+
})
|
|
43
67
|
.orElse(() => (0, neverthrow_1.okAsync)(null));
|
|
44
68
|
}
|
|
45
|
-
function
|
|
69
|
+
function safeSnapshotRef(raw) {
|
|
70
|
+
if (!raw || !constants_js_1.SHA256_DIGEST_PATTERN.test(raw))
|
|
71
|
+
return null;
|
|
72
|
+
return (0, index_js_1.asSnapshotRef)((0, index_js_1.asSha256Digest)(raw));
|
|
73
|
+
}
|
|
74
|
+
function projectSessionSummary(sessionId, truth, mtimeMs) {
|
|
46
75
|
const health = (0, session_health_js_1.projectSessionHealthV2)(truth);
|
|
47
76
|
if (health.isErr() || health.value.kind !== 'healthy')
|
|
48
77
|
return null;
|
|
@@ -60,15 +89,21 @@ function projectSessionSummary(sessionId, truth) {
|
|
|
60
89
|
? extractAggregateRecap(outputsRes.value, bestRun.run, bestRun.tipNodeId)
|
|
61
90
|
: null;
|
|
62
91
|
return {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
92
|
+
summary: {
|
|
93
|
+
sessionId,
|
|
94
|
+
runId: bestRun.run.runId,
|
|
95
|
+
preferredTip: {
|
|
96
|
+
nodeId: bestRun.tipNodeId,
|
|
97
|
+
lastActivityEventIndex: bestRun.lastActivityEventIndex,
|
|
98
|
+
},
|
|
99
|
+
recapSnippet,
|
|
100
|
+
observations: extractObservations(truth.events),
|
|
101
|
+
workflow,
|
|
102
|
+
lastModifiedMs: mtimeMs,
|
|
103
|
+
pendingStepId: null,
|
|
104
|
+
isComplete: false,
|
|
68
105
|
},
|
|
69
|
-
|
|
70
|
-
observations: extractObservations(truth.events),
|
|
71
|
-
workflow,
|
|
106
|
+
tipSnapshotRef: bestRun.tipSnapshotRef,
|
|
72
107
|
};
|
|
73
108
|
}
|
|
74
109
|
function selectBestRun(runs) {
|
|
@@ -77,7 +112,9 @@ function selectBestRun(runs) {
|
|
|
77
112
|
if (!tipNodeId)
|
|
78
113
|
return [];
|
|
79
114
|
const tipNode = r.nodesById[tipNodeId];
|
|
80
|
-
|
|
115
|
+
if (!tipNode)
|
|
116
|
+
return [];
|
|
117
|
+
return [{ run: r, tipNodeId, tipSnapshotRef: tipNode.snapshotRef, lastActivityEventIndex: tipNode.createdAtEventIndex }];
|
|
81
118
|
});
|
|
82
119
|
if (runsWithTip.length === 0)
|
|
83
120
|
return null;
|
|
@@ -28,9 +28,16 @@ export interface HealthySessionSummary {
|
|
|
28
28
|
readonly recapSnippet: RecapSnippet | null;
|
|
29
29
|
readonly observations: SessionObservations;
|
|
30
30
|
readonly workflow: IdentifiedWorkflow;
|
|
31
|
+
readonly lastModifiedMs: number | null;
|
|
32
|
+
readonly pendingStepId: string | null;
|
|
33
|
+
readonly isComplete: boolean;
|
|
31
34
|
}
|
|
32
|
-
export type WhyMatched = 'matched_head_sha' | 'matched_branch' | 'matched_notes' | 'matched_workflow_id' | 'recency_fallback';
|
|
35
|
+
export type WhyMatched = 'matched_exact_id' | 'matched_head_sha' | 'matched_branch' | 'matched_notes' | 'matched_notes_partial' | 'matched_workflow_id' | 'recency_fallback';
|
|
33
36
|
export type TierAssignment = {
|
|
37
|
+
readonly tier: 0;
|
|
38
|
+
readonly kind: 'matched_exact_id';
|
|
39
|
+
readonly matchField: 'runId' | 'sessionId';
|
|
40
|
+
} | {
|
|
34
41
|
readonly tier: 1;
|
|
35
42
|
readonly kind: 'matched_head_sha';
|
|
36
43
|
} | {
|
|
@@ -42,17 +49,26 @@ export type TierAssignment = {
|
|
|
42
49
|
readonly kind: 'matched_notes';
|
|
43
50
|
} | {
|
|
44
51
|
readonly tier: 4;
|
|
45
|
-
readonly kind: '
|
|
52
|
+
readonly kind: 'matched_notes_partial';
|
|
53
|
+
readonly matchRatio: number;
|
|
46
54
|
} | {
|
|
47
55
|
readonly tier: 5;
|
|
56
|
+
readonly kind: 'matched_workflow_id';
|
|
57
|
+
} | {
|
|
58
|
+
readonly tier: 6;
|
|
48
59
|
readonly kind: 'recency_fallback';
|
|
49
60
|
};
|
|
50
61
|
export declare function normalizeToTokens(text: string): ReadonlySet<string>;
|
|
51
62
|
export declare function allQueryTokensMatch(queryTokens: ReadonlySet<string>, candidateTokens: ReadonlySet<string>): boolean;
|
|
63
|
+
export declare function queryTokenMatchRatio(queryTokens: ReadonlySet<string>, candidateTokens: ReadonlySet<string>): number;
|
|
64
|
+
export declare function fuzzyTokenMatch(queryToken: string, candidateTokens: ReadonlySet<string>): boolean;
|
|
65
|
+
export declare function fuzzyQueryTokenMatchRatio(queryTokens: ReadonlySet<string>, candidateTokens: ReadonlySet<string>): number;
|
|
52
66
|
export interface ResumeQuery {
|
|
53
67
|
readonly gitHeadSha?: string;
|
|
54
68
|
readonly gitBranch?: string;
|
|
55
69
|
readonly freeTextQuery?: string;
|
|
70
|
+
readonly runId?: string;
|
|
71
|
+
readonly sessionId?: string;
|
|
56
72
|
}
|
|
57
73
|
export declare function assignTier(summary: HealthySessionSummary, query: ResumeQuery): TierAssignment;
|
|
58
74
|
export interface RankedResumeCandidate {
|
|
@@ -65,6 +81,9 @@ export interface RankedResumeCandidate {
|
|
|
65
81
|
readonly lastActivityEventIndex: number;
|
|
66
82
|
readonly workflowHash: WorkflowHash;
|
|
67
83
|
readonly workflowId: WorkflowId;
|
|
84
|
+
readonly pendingStepId: string | null;
|
|
85
|
+
readonly isComplete: boolean;
|
|
86
|
+
readonly lastModifiedMs: number | null;
|
|
68
87
|
}
|
|
69
88
|
export declare const MAX_RESUME_CANDIDATES = 5;
|
|
70
89
|
export declare function rankResumeCandidates(summaries: readonly HealthySessionSummary[], query: ResumeQuery): readonly RankedResumeCandidate[];
|
|
@@ -4,6 +4,9 @@ exports.MAX_RESUME_CANDIDATES = void 0;
|
|
|
4
4
|
exports.asRecapSnippet = asRecapSnippet;
|
|
5
5
|
exports.normalizeToTokens = normalizeToTokens;
|
|
6
6
|
exports.allQueryTokensMatch = allQueryTokensMatch;
|
|
7
|
+
exports.queryTokenMatchRatio = queryTokenMatchRatio;
|
|
8
|
+
exports.fuzzyTokenMatch = fuzzyTokenMatch;
|
|
9
|
+
exports.fuzzyQueryTokenMatchRatio = fuzzyQueryTokenMatchRatio;
|
|
7
10
|
exports.assignTier = assignTier;
|
|
8
11
|
exports.rankResumeCandidates = rankResumeCandidates;
|
|
9
12
|
const constants_js_1 = require("../durable-core/constants.js");
|
|
@@ -36,7 +39,45 @@ function allQueryTokensMatch(queryTokens, candidateTokens) {
|
|
|
36
39
|
}
|
|
37
40
|
return true;
|
|
38
41
|
}
|
|
42
|
+
function queryTokenMatchRatio(queryTokens, candidateTokens) {
|
|
43
|
+
if (queryTokens.size === 0 || candidateTokens.size === 0)
|
|
44
|
+
return 0;
|
|
45
|
+
let matched = 0;
|
|
46
|
+
for (const token of queryTokens) {
|
|
47
|
+
if (candidateTokens.has(token))
|
|
48
|
+
matched++;
|
|
49
|
+
}
|
|
50
|
+
return matched / queryTokens.size;
|
|
51
|
+
}
|
|
52
|
+
function fuzzyTokenMatch(queryToken, candidateTokens) {
|
|
53
|
+
if (queryToken.length < 3)
|
|
54
|
+
return false;
|
|
55
|
+
for (const ct of candidateTokens) {
|
|
56
|
+
if (ct.length < 3)
|
|
57
|
+
continue;
|
|
58
|
+
if (ct.includes(queryToken) || queryToken.includes(ct))
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
function fuzzyQueryTokenMatchRatio(queryTokens, candidateTokens) {
|
|
64
|
+
if (queryTokens.size === 0 || candidateTokens.size === 0)
|
|
65
|
+
return 0;
|
|
66
|
+
let matched = 0;
|
|
67
|
+
for (const qt of queryTokens) {
|
|
68
|
+
if (candidateTokens.has(qt) || fuzzyTokenMatch(qt, candidateTokens))
|
|
69
|
+
matched++;
|
|
70
|
+
}
|
|
71
|
+
return matched / queryTokens.size;
|
|
72
|
+
}
|
|
73
|
+
const MIN_PARTIAL_MATCH_RATIO = 0.4;
|
|
39
74
|
function assignTier(summary, query) {
|
|
75
|
+
if (query.runId && summary.runId === query.runId) {
|
|
76
|
+
return { tier: 0, kind: 'matched_exact_id', matchField: 'runId' };
|
|
77
|
+
}
|
|
78
|
+
if (query.sessionId && String(summary.sessionId) === query.sessionId) {
|
|
79
|
+
return { tier: 0, kind: 'matched_exact_id', matchField: 'sessionId' };
|
|
80
|
+
}
|
|
40
81
|
if (query.gitHeadSha && summary.observations.gitHeadSha === query.gitHeadSha) {
|
|
41
82
|
return { tier: 1, kind: 'matched_head_sha' };
|
|
42
83
|
}
|
|
@@ -49,27 +90,36 @@ function assignTier(summary, query) {
|
|
|
49
90
|
return { tier: 2, kind: 'matched_branch', matchType: 'prefix' };
|
|
50
91
|
}
|
|
51
92
|
}
|
|
52
|
-
|
|
53
|
-
|
|
93
|
+
const queryTokens = query.freeTextQuery ? normalizeToTokens(query.freeTextQuery) : null;
|
|
94
|
+
if (queryTokens && queryTokens.size > 0 && summary.recapSnippet) {
|
|
54
95
|
const noteTokens = normalizeToTokens(summary.recapSnippet);
|
|
55
96
|
if (allQueryTokensMatch(queryTokens, noteTokens)) {
|
|
56
97
|
return { tier: 3, kind: 'matched_notes' };
|
|
57
98
|
}
|
|
99
|
+
const ratio = fuzzyQueryTokenMatchRatio(queryTokens, noteTokens);
|
|
100
|
+
if (ratio >= MIN_PARTIAL_MATCH_RATIO) {
|
|
101
|
+
return { tier: 4, kind: 'matched_notes_partial', matchRatio: ratio };
|
|
102
|
+
}
|
|
58
103
|
}
|
|
59
|
-
if (
|
|
60
|
-
const queryTokens = normalizeToTokens(query.freeTextQuery);
|
|
104
|
+
if (queryTokens && queryTokens.size > 0 && summary.workflow.kind === 'identified') {
|
|
61
105
|
const workflowTokens = normalizeToTokens(String(summary.workflow.workflowId));
|
|
62
106
|
if (allQueryTokensMatch(queryTokens, workflowTokens)) {
|
|
63
|
-
return { tier:
|
|
107
|
+
return { tier: 5, kind: 'matched_workflow_id' };
|
|
108
|
+
}
|
|
109
|
+
const ratio = fuzzyQueryTokenMatchRatio(queryTokens, workflowTokens);
|
|
110
|
+
if (ratio >= MIN_PARTIAL_MATCH_RATIO) {
|
|
111
|
+
return { tier: 5, kind: 'matched_workflow_id' };
|
|
64
112
|
}
|
|
65
113
|
}
|
|
66
|
-
return { tier:
|
|
114
|
+
return { tier: 6, kind: 'recency_fallback' };
|
|
67
115
|
}
|
|
68
116
|
function tierToWhyMatched(tier) {
|
|
69
117
|
switch (tier.kind) {
|
|
118
|
+
case 'matched_exact_id': return 'matched_exact_id';
|
|
70
119
|
case 'matched_head_sha': return 'matched_head_sha';
|
|
71
120
|
case 'matched_branch': return 'matched_branch';
|
|
72
121
|
case 'matched_notes': return 'matched_notes';
|
|
122
|
+
case 'matched_notes_partial': return 'matched_notes_partial';
|
|
73
123
|
case 'matched_workflow_id': return 'matched_workflow_id';
|
|
74
124
|
case 'recency_fallback': return 'recency_fallback';
|
|
75
125
|
}
|
|
@@ -83,6 +133,13 @@ function rankResumeCandidates(summaries, query) {
|
|
|
83
133
|
const sorted = [...withTier].sort((a, b) => {
|
|
84
134
|
if (a.tier.tier !== b.tier.tier)
|
|
85
135
|
return a.tier.tier - b.tier.tier;
|
|
136
|
+
if (a.summary.isComplete !== b.summary.isComplete) {
|
|
137
|
+
return a.summary.isComplete ? 1 : -1;
|
|
138
|
+
}
|
|
139
|
+
if (a.tier.kind === 'matched_notes_partial' && b.tier.kind === 'matched_notes_partial') {
|
|
140
|
+
if (a.tier.matchRatio !== b.tier.matchRatio)
|
|
141
|
+
return b.tier.matchRatio - a.tier.matchRatio;
|
|
142
|
+
}
|
|
86
143
|
const actA = a.summary.preferredTip.lastActivityEventIndex;
|
|
87
144
|
const actB = b.summary.preferredTip.lastActivityEventIndex;
|
|
88
145
|
if (actA !== actB)
|
|
@@ -99,5 +156,8 @@ function rankResumeCandidates(summaries, query) {
|
|
|
99
156
|
lastActivityEventIndex: summary.preferredTip.lastActivityEventIndex,
|
|
100
157
|
workflowHash: summary.workflow.workflowHash,
|
|
101
158
|
workflowId: summary.workflow.workflowId,
|
|
159
|
+
pendingStepId: summary.pendingStepId,
|
|
160
|
+
isComplete: summary.isComplete,
|
|
161
|
+
lastModifiedMs: summary.lastModifiedMs,
|
|
102
162
|
}));
|
|
103
163
|
}
|
|
@@ -7,7 +7,11 @@ export declare function enumerateSessions(ports: {
|
|
|
7
7
|
readonly directoryListing: DirectoryListingPortV2;
|
|
8
8
|
readonly dataDir: DataDirPortV2;
|
|
9
9
|
}): ResultAsync<readonly SessionId[], FsError>;
|
|
10
|
+
export interface SessionWithMtime {
|
|
11
|
+
readonly sessionId: SessionId;
|
|
12
|
+
readonly mtimeMs: number;
|
|
13
|
+
}
|
|
10
14
|
export declare function enumerateSessionsByRecency(ports: {
|
|
11
15
|
readonly directoryListing: DirectoryListingPortV2;
|
|
12
16
|
readonly dataDir: DataDirPortV2;
|
|
13
|
-
}): ResultAsync<readonly
|
|
17
|
+
}): ResultAsync<readonly SessionWithMtime[], FsError>;
|
|
@@ -22,5 +22,5 @@ function enumerateSessionsByRecency(ports) {
|
|
|
22
22
|
return b.mtimeMs - a.mtimeMs;
|
|
23
23
|
return a.name.localeCompare(b.name);
|
|
24
24
|
})
|
|
25
|
-
.map((entry) => (0, index_js_1.asSessionId)(entry.name)));
|
|
25
|
+
.map((entry) => ({ sessionId: (0, index_js_1.asSessionId)(entry.name), mtimeMs: entry.mtimeMs })));
|
|
26
26
|
}
|