@mrtdown/core 2.0.0-alpha.5 → 2.0.0-alpha.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (250) hide show
  1. package/dist/index.d.ts +0 -7
  2. package/dist/index.js +0 -7
  3. package/dist/index.js.map +1 -1
  4. package/dist/schema/Landmark.js.map +1 -1
  5. package/dist/schema/Line.js.map +1 -1
  6. package/dist/schema/Operator.js.map +1 -1
  7. package/dist/schema/Service.js.map +1 -1
  8. package/dist/schema/Station.js.map +1 -1
  9. package/dist/schema/Town.js.map +1 -1
  10. package/dist/schema/common.js.map +1 -1
  11. package/dist/schema/issue/bundle.js.map +1 -1
  12. package/dist/schema/issue/cause.js.map +1 -1
  13. package/dist/schema/issue/claim.js.map +1 -1
  14. package/dist/schema/issue/entity.js.map +1 -1
  15. package/dist/schema/issue/evidence.js.map +1 -1
  16. package/dist/schema/issue/facilityEffect.js.map +1 -1
  17. package/dist/schema/issue/id.js.map +1 -1
  18. package/dist/schema/issue/impactEvent.js.map +1 -1
  19. package/dist/schema/issue/issue.js.map +1 -1
  20. package/dist/schema/issue/issueType.js.map +1 -1
  21. package/dist/schema/issue/period.js.map +1 -1
  22. package/dist/schema/issue/serviceEffect.js.map +1 -1
  23. package/dist/schema/issue/serviceScope.js.map +1 -1
  24. package/package.json +19 -44
  25. package/README.md +0 -107
  26. package/dist/cli/commands/create.d.ts +0 -30
  27. package/dist/cli/commands/create.js +0 -189
  28. package/dist/cli/commands/create.js.map +0 -1
  29. package/dist/cli/commands/list.d.ts +0 -6
  30. package/dist/cli/commands/list.js +0 -106
  31. package/dist/cli/commands/list.js.map +0 -1
  32. package/dist/cli/commands/show.d.ts +0 -6
  33. package/dist/cli/commands/show.js +0 -156
  34. package/dist/cli/commands/show.js.map +0 -1
  35. package/dist/cli/commands/validate.d.ts +0 -6
  36. package/dist/cli/commands/validate.js +0 -19
  37. package/dist/cli/commands/validate.js.map +0 -1
  38. package/dist/cli/index.d.ts +0 -2
  39. package/dist/cli/index.js +0 -162
  40. package/dist/cli/index.js.map +0 -1
  41. package/dist/constants.d.ts +0 -10
  42. package/dist/constants.js +0 -11
  43. package/dist/constants.js.map +0 -1
  44. package/dist/helpers/calculateDurationWithinServiceHours.d.ts +0 -2
  45. package/dist/helpers/calculateDurationWithinServiceHours.js +0 -13
  46. package/dist/helpers/calculateDurationWithinServiceHours.js.map +0 -1
  47. package/dist/helpers/calculateDurationWithinServiceHours.test.d.ts +0 -1
  48. package/dist/helpers/calculateDurationWithinServiceHours.test.js +0 -83
  49. package/dist/helpers/calculateDurationWithinServiceHours.test.js.map +0 -1
  50. package/dist/helpers/computeImpactFromEvidenceClaims.d.ts +0 -21
  51. package/dist/helpers/computeImpactFromEvidenceClaims.js +0 -293
  52. package/dist/helpers/computeImpactFromEvidenceClaims.js.map +0 -1
  53. package/dist/helpers/computeImpactFromEvidenceClaims.test.d.ts +0 -1
  54. package/dist/helpers/computeImpactFromEvidenceClaims.test.js +0 -544
  55. package/dist/helpers/computeImpactFromEvidenceClaims.test.js.map +0 -1
  56. package/dist/helpers/computeStartOfDaysWithinInterval.d.ts +0 -2
  57. package/dist/helpers/computeStartOfDaysWithinInterval.js +0 -15
  58. package/dist/helpers/computeStartOfDaysWithinInterval.js.map +0 -1
  59. package/dist/helpers/computeStartOfDaysWithinInterval.test.d.ts +0 -1
  60. package/dist/helpers/computeStartOfDaysWithinInterval.test.js +0 -126
  61. package/dist/helpers/computeStartOfDaysWithinInterval.test.js.map +0 -1
  62. package/dist/helpers/estimateOpenAICost.d.ts +0 -40
  63. package/dist/helpers/estimateOpenAICost.js +0 -55
  64. package/dist/helpers/estimateOpenAICost.js.map +0 -1
  65. package/dist/helpers/keyForAffectedEntity.d.ts +0 -7
  66. package/dist/helpers/keyForAffectedEntity.js +0 -14
  67. package/dist/helpers/keyForAffectedEntity.js.map +0 -1
  68. package/dist/helpers/normalizeRecurringPeriod.d.ts +0 -7
  69. package/dist/helpers/normalizeRecurringPeriod.js +0 -118
  70. package/dist/helpers/normalizeRecurringPeriod.js.map +0 -1
  71. package/dist/helpers/normalizeRecurringPeriod.test.d.ts +0 -1
  72. package/dist/helpers/normalizeRecurringPeriod.test.js +0 -93
  73. package/dist/helpers/normalizeRecurringPeriod.test.js.map +0 -1
  74. package/dist/helpers/resolvePeriods.d.ts +0 -224
  75. package/dist/helpers/resolvePeriods.js +0 -207
  76. package/dist/helpers/resolvePeriods.js.map +0 -1
  77. package/dist/helpers/resolvePeriods.test.d.ts +0 -1
  78. package/dist/helpers/resolvePeriods.test.js +0 -239
  79. package/dist/helpers/resolvePeriods.test.js.map +0 -1
  80. package/dist/helpers/splitIntervalByServiceHours.d.ts +0 -2
  81. package/dist/helpers/splitIntervalByServiceHours.js +0 -30
  82. package/dist/helpers/splitIntervalByServiceHours.js.map +0 -1
  83. package/dist/helpers/splitIntervalByServiceHours.test.d.ts +0 -1
  84. package/dist/helpers/splitIntervalByServiceHours.test.js +0 -152
  85. package/dist/helpers/splitIntervalByServiceHours.test.js.map +0 -1
  86. package/dist/helpers/sumIntervalDuration.d.ts +0 -2
  87. package/dist/helpers/sumIntervalDuration.js +0 -9
  88. package/dist/helpers/sumIntervalDuration.js.map +0 -1
  89. package/dist/llm/client.d.ts +0 -2
  90. package/dist/llm/client.js +0 -5
  91. package/dist/llm/client.js.map +0 -1
  92. package/dist/llm/common/MemoryStore.d.ts +0 -21
  93. package/dist/llm/common/MemoryStore.js +0 -100
  94. package/dist/llm/common/MemoryStore.js.map +0 -1
  95. package/dist/llm/common/MemoryStore.test.d.ts +0 -1
  96. package/dist/llm/common/MemoryStore.test.js +0 -225
  97. package/dist/llm/common/MemoryStore.test.js.map +0 -1
  98. package/dist/llm/common/formatCurrentState.d.ts +0 -10
  99. package/dist/llm/common/formatCurrentState.js +0 -342
  100. package/dist/llm/common/formatCurrentState.js.map +0 -1
  101. package/dist/llm/common/tool.d.ts +0 -32
  102. package/dist/llm/common/tool.js +0 -6
  103. package/dist/llm/common/tool.js.map +0 -1
  104. package/dist/llm/functions/extractClaimsFromNewEvidence/eval.test.d.ts +0 -1
  105. package/dist/llm/functions/extractClaimsFromNewEvidence/eval.test.js +0 -433
  106. package/dist/llm/functions/extractClaimsFromNewEvidence/eval.test.js.map +0 -1
  107. package/dist/llm/functions/extractClaimsFromNewEvidence/index.d.ts +0 -18
  108. package/dist/llm/functions/extractClaimsFromNewEvidence/index.js +0 -153
  109. package/dist/llm/functions/extractClaimsFromNewEvidence/index.js.map +0 -1
  110. package/dist/llm/functions/extractClaimsFromNewEvidence/prompt.d.ts +0 -1
  111. package/dist/llm/functions/extractClaimsFromNewEvidence/prompt.js +0 -168
  112. package/dist/llm/functions/extractClaimsFromNewEvidence/prompt.js.map +0 -1
  113. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindLinesTool.d.ts +0 -19
  114. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindLinesTool.js +0 -65
  115. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindLinesTool.js.map +0 -1
  116. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindServicesTool.d.ts +0 -21
  117. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindServicesTool.js +0 -115
  118. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindServicesTool.js.map +0 -1
  119. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindStationsTool.d.ts +0 -24
  120. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindStationsTool.js +0 -110
  121. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindStationsTool.js.map +0 -1
  122. package/dist/llm/functions/generateIssueTitleAndSlug/index.d.ts +0 -14
  123. package/dist/llm/functions/generateIssueTitleAndSlug/index.js +0 -38
  124. package/dist/llm/functions/generateIssueTitleAndSlug/index.js.map +0 -1
  125. package/dist/llm/functions/generateIssueTitleAndSlug/prompt.d.ts +0 -1
  126. package/dist/llm/functions/generateIssueTitleAndSlug/prompt.js +0 -23
  127. package/dist/llm/functions/generateIssueTitleAndSlug/prompt.js.map +0 -1
  128. package/dist/llm/functions/translate/index.d.ts +0 -1
  129. package/dist/llm/functions/translate/index.js +0 -59
  130. package/dist/llm/functions/translate/index.js.map +0 -1
  131. package/dist/llm/functions/triageNewEvidence/eval.test.d.ts +0 -1
  132. package/dist/llm/functions/triageNewEvidence/eval.test.js +0 -139
  133. package/dist/llm/functions/triageNewEvidence/eval.test.js.map +0 -1
  134. package/dist/llm/functions/triageNewEvidence/index.d.ts +0 -37
  135. package/dist/llm/functions/triageNewEvidence/index.js +0 -121
  136. package/dist/llm/functions/triageNewEvidence/index.js.map +0 -1
  137. package/dist/llm/functions/triageNewEvidence/prompt.d.ts +0 -1
  138. package/dist/llm/functions/triageNewEvidence/prompt.js +0 -60
  139. package/dist/llm/functions/triageNewEvidence/prompt.js.map +0 -1
  140. package/dist/llm/functions/triageNewEvidence/tools/FindIssuesTool.d.ts +0 -19
  141. package/dist/llm/functions/triageNewEvidence/tools/FindIssuesTool.js +0 -65
  142. package/dist/llm/functions/triageNewEvidence/tools/FindIssuesTool.js.map +0 -1
  143. package/dist/llm/functions/triageNewEvidence/tools/GetIssueTool.d.ts +0 -19
  144. package/dist/llm/functions/triageNewEvidence/tools/GetIssueTool.js +0 -37
  145. package/dist/llm/functions/triageNewEvidence/tools/GetIssueTool.js.map +0 -1
  146. package/dist/repo/MRTDownRepository.d.ts +0 -23
  147. package/dist/repo/MRTDownRepository.js +0 -28
  148. package/dist/repo/MRTDownRepository.js.map +0 -1
  149. package/dist/repo/common/FileStore.d.ts +0 -12
  150. package/dist/repo/common/FileStore.js +0 -27
  151. package/dist/repo/common/FileStore.js.map +0 -1
  152. package/dist/repo/common/StandardRepository.d.ts +0 -32
  153. package/dist/repo/common/StandardRepository.js +0 -58
  154. package/dist/repo/common/StandardRepository.js.map +0 -1
  155. package/dist/repo/common/store.d.ts +0 -29
  156. package/dist/repo/common/store.js +0 -2
  157. package/dist/repo/common/store.js.map +0 -1
  158. package/dist/repo/issue/IssueRepository.d.ts +0 -36
  159. package/dist/repo/issue/IssueRepository.js +0 -177
  160. package/dist/repo/issue/IssueRepository.js.map +0 -1
  161. package/dist/repo/issue/helpers/deriveCurrentState.d.ts +0 -51
  162. package/dist/repo/issue/helpers/deriveCurrentState.js +0 -113
  163. package/dist/repo/issue/helpers/deriveCurrentState.js.map +0 -1
  164. package/dist/repo/issue/helpers/deriveCurrentState.test.d.ts +0 -1
  165. package/dist/repo/issue/helpers/deriveCurrentState.test.js +0 -477
  166. package/dist/repo/issue/helpers/deriveCurrentState.test.js.map +0 -1
  167. package/dist/repo/landmark/LandmarkRepository.d.ts +0 -7
  168. package/dist/repo/landmark/LandmarkRepository.js +0 -12
  169. package/dist/repo/landmark/LandmarkRepository.js.map +0 -1
  170. package/dist/repo/line/LineRepository.d.ts +0 -13
  171. package/dist/repo/line/LineRepository.js +0 -32
  172. package/dist/repo/line/LineRepository.js.map +0 -1
  173. package/dist/repo/operator/OperatorRepository.d.ts +0 -7
  174. package/dist/repo/operator/OperatorRepository.js +0 -12
  175. package/dist/repo/operator/OperatorRepository.js.map +0 -1
  176. package/dist/repo/service/ServiceRepository.d.ts +0 -19
  177. package/dist/repo/service/ServiceRepository.js +0 -39
  178. package/dist/repo/service/ServiceRepository.js.map +0 -1
  179. package/dist/repo/station/StationRepository.d.ts +0 -13
  180. package/dist/repo/station/StationRepository.js +0 -30
  181. package/dist/repo/station/StationRepository.js.map +0 -1
  182. package/dist/repo/town/TownRepository.d.ts +0 -7
  183. package/dist/repo/town/TownRepository.js +0 -12
  184. package/dist/repo/town/TownRepository.js.map +0 -1
  185. package/dist/scripts/ingestViaWebhook.d.ts +0 -1
  186. package/dist/scripts/ingestViaWebhook.js +0 -9
  187. package/dist/scripts/ingestViaWebhook.js.map +0 -1
  188. package/dist/util/assert.d.ts +0 -1
  189. package/dist/util/assert.js +0 -6
  190. package/dist/util/assert.js.map +0 -1
  191. package/dist/util/ingestContent/helpers/getSlugDateTimeFromClaims.d.ts +0 -7
  192. package/dist/util/ingestContent/helpers/getSlugDateTimeFromClaims.js +0 -24
  193. package/dist/util/ingestContent/helpers/getSlugDateTimeFromClaims.js.map +0 -1
  194. package/dist/util/ingestContent/index.d.ts +0 -12
  195. package/dist/util/ingestContent/index.js +0 -171
  196. package/dist/util/ingestContent/index.js.map +0 -1
  197. package/dist/util/ingestContent/types.d.ts +0 -32
  198. package/dist/util/ingestContent/types.js +0 -2
  199. package/dist/util/ingestContent/types.js.map +0 -1
  200. package/dist/validators/buildContext.d.ts +0 -7
  201. package/dist/validators/buildContext.js +0 -164
  202. package/dist/validators/buildContext.js.map +0 -1
  203. package/dist/validators/index.d.ts +0 -17
  204. package/dist/validators/index.js +0 -58
  205. package/dist/validators/index.js.map +0 -1
  206. package/dist/validators/issue.d.ts +0 -13
  207. package/dist/validators/issue.js +0 -220
  208. package/dist/validators/issue.js.map +0 -1
  209. package/dist/validators/landmark.d.ts +0 -7
  210. package/dist/validators/landmark.js +0 -43
  211. package/dist/validators/landmark.js.map +0 -1
  212. package/dist/validators/line.d.ts +0 -8
  213. package/dist/validators/line.js +0 -87
  214. package/dist/validators/line.js.map +0 -1
  215. package/dist/validators/operator.d.ts +0 -7
  216. package/dist/validators/operator.js +0 -43
  217. package/dist/validators/operator.js.map +0 -1
  218. package/dist/validators/service.d.ts +0 -8
  219. package/dist/validators/service.js +0 -87
  220. package/dist/validators/service.js.map +0 -1
  221. package/dist/validators/station.d.ts +0 -8
  222. package/dist/validators/station.js +0 -93
  223. package/dist/validators/station.js.map +0 -1
  224. package/dist/validators/town.d.ts +0 -7
  225. package/dist/validators/town.js +0 -43
  226. package/dist/validators/town.js.map +0 -1
  227. package/dist/validators/types.d.ts +0 -19
  228. package/dist/validators/types.js +0 -2
  229. package/dist/validators/types.js.map +0 -1
  230. package/dist/validators/utils.d.ts +0 -2
  231. package/dist/validators/utils.js +0 -9
  232. package/dist/validators/utils.js.map +0 -1
  233. package/dist/write/MRTDownWriter.d.ts +0 -27
  234. package/dist/write/MRTDownWriter.js +0 -27
  235. package/dist/write/MRTDownWriter.js.map +0 -1
  236. package/dist/write/common/FileWriteStore.d.ts +0 -13
  237. package/dist/write/common/FileWriteStore.js +0 -31
  238. package/dist/write/common/FileWriteStore.js.map +0 -1
  239. package/dist/write/common/StandardWriter.d.ts +0 -14
  240. package/dist/write/common/StandardWriter.js +0 -17
  241. package/dist/write/common/StandardWriter.js.map +0 -1
  242. package/dist/write/common/store.d.ts +0 -32
  243. package/dist/write/common/store.js +0 -2
  244. package/dist/write/common/store.js.map +0 -1
  245. package/dist/write/id/IdGenerator.d.ts +0 -18
  246. package/dist/write/id/IdGenerator.js +0 -23
  247. package/dist/write/id/IdGenerator.js.map +0 -1
  248. package/dist/write/issue/IssueWriter.d.ts +0 -12
  249. package/dist/write/issue/IssueWriter.js +0 -33
  250. package/dist/write/issue/IssueWriter.js.map +0 -1
@@ -1,24 +0,0 @@
1
- import { DateTime } from 'luxon';
2
- import z from 'zod';
3
- import { Tool } from '../../../common/tool.js';
4
- import type { MRTDownRepository } from '../../../../repo/MRTDownRepository.js';
5
- declare const FindStationsToolParametersSchema: z.ZodObject<{
6
- stationNames: z.ZodArray<z.ZodString>;
7
- }, z.z.core.$strip>;
8
- type FindStationsToolParameters = z.infer<typeof FindStationsToolParametersSchema>;
9
- export declare class FindStationsTool extends Tool<FindStationsToolParameters> {
10
- name: string;
11
- description: string;
12
- private readonly repo;
13
- get paramsSchema(): {
14
- [key: string]: unknown;
15
- };
16
- parseParams(params: unknown): FindStationsToolParameters;
17
- /**
18
- * The timestamp of the evidence.
19
- */
20
- private evidenceTs;
21
- constructor(evidenceTs: DateTime, repo: MRTDownRepository);
22
- runner(params: FindStationsToolParameters): Promise<string>;
23
- }
24
- export {};
@@ -1,110 +0,0 @@
1
- import { DateTime } from 'luxon';
2
- import { gfmToMarkdown } from 'mdast-util-gfm';
3
- import { toMarkdown } from 'mdast-util-to-markdown';
4
- import z from 'zod';
5
- import { Tool } from '../../../common/tool.js';
6
- import { assert } from '../../../../util/assert.js';
7
- const FindStationsToolParametersSchema = z.object({
8
- stationNames: z.array(z.string()),
9
- });
10
- export class FindStationsTool extends Tool {
11
- name = 'findStations';
12
- description = 'Find stations by name';
13
- repo;
14
- get paramsSchema() {
15
- return z.toJSONSchema(FindStationsToolParametersSchema);
16
- }
17
- parseParams(params) {
18
- return FindStationsToolParametersSchema.parse(params);
19
- }
20
- /**
21
- * The timestamp of the evidence.
22
- */
23
- evidenceTs;
24
- constructor(evidenceTs, repo) {
25
- super();
26
- this.evidenceTs = evidenceTs;
27
- this.repo = repo;
28
- }
29
- async runner(params) {
30
- console.log('[findStations] Calling tool with parameters:', params);
31
- const stations = this.repo.stations.searchByName(params.stationNames);
32
- const table = {
33
- type: 'table',
34
- children: [
35
- {
36
- type: 'tableRow',
37
- children: [
38
- {
39
- type: 'tableCell',
40
- children: [{ type: 'text', value: 'Station ID' }],
41
- },
42
- {
43
- type: 'tableCell',
44
- children: [{ type: 'text', value: 'Station Name' }],
45
- },
46
- {
47
- type: 'tableCell',
48
- children: [{ type: 'text', value: 'Station Codes' }],
49
- },
50
- {
51
- type: 'tableCell',
52
- children: [{ type: 'text', value: 'Line IDs' }],
53
- },
54
- ],
55
- },
56
- ],
57
- };
58
- for (const station of stations) {
59
- const relevantStationCodes = station.stationCodes.filter((membership) => {
60
- const startedAt = DateTime.fromISO(membership.startedAt);
61
- assert(startedAt.isValid, `Invalid date: ${membership.startedAt}`);
62
- if (startedAt > this.evidenceTs)
63
- return false;
64
- if (membership.endedAt != null &&
65
- DateTime.fromISO(membership.endedAt) < this.evidenceTs)
66
- return false;
67
- return true;
68
- });
69
- const stationCodesSet = new Set(relevantStationCodes.map((membership) => membership.code));
70
- const lineIds = relevantStationCodes.map((membership) => membership.lineId);
71
- table.children.push({
72
- type: 'tableRow',
73
- children: [
74
- {
75
- type: 'tableCell',
76
- children: [{ type: 'text', value: station.id }],
77
- },
78
- {
79
- type: 'tableCell',
80
- children: [{ type: 'text', value: station.name['en-SG'] }],
81
- },
82
- {
83
- type: 'tableCell',
84
- children: [
85
- {
86
- type: 'text',
87
- value: Array.from(stationCodesSet).join(', '),
88
- },
89
- ],
90
- },
91
- {
92
- type: 'tableCell',
93
- children: [
94
- {
95
- type: 'text',
96
- value: lineIds.join(', '),
97
- },
98
- ],
99
- },
100
- ],
101
- });
102
- }
103
- const output = toMarkdown(table, {
104
- extensions: [gfmToMarkdown()],
105
- });
106
- console.log(`[findStations] Response output:\n${output}`);
107
- return output;
108
- }
109
- }
110
- //# sourceMappingURL=FindStationsTool.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"FindStationsTool.js","sourceRoot":"/","sources":["llm/functions/extractClaimsFromNewEvidence/tools/FindStationsTool.ts"],"names":[],"mappings":"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","sourcesContent":["import { DateTime } from 'luxon';\nimport type { Table } from 'mdast';\nimport { gfmToMarkdown } from 'mdast-util-gfm';\nimport { toMarkdown } from 'mdast-util-to-markdown';\nimport z from 'zod';\nimport { Tool } from '../../../common/tool.js';\nimport type { MRTDownRepository } from '../../../../repo/MRTDownRepository.js';\nimport { assert } from '../../../../util/assert.js';\n\nconst FindStationsToolParametersSchema = z.object({\n stationNames: z.array(z.string()),\n});\ntype FindStationsToolParameters = z.infer<\n typeof FindStationsToolParametersSchema\n>;\n\nexport class FindStationsTool extends Tool<FindStationsToolParameters> {\n public name = 'findStations';\n public description = 'Find stations by name';\n private readonly repo: MRTDownRepository;\n\n public get paramsSchema(): { [key: string]: unknown } {\n return z.toJSONSchema(FindStationsToolParametersSchema);\n }\n\n public parseParams(params: unknown): FindStationsToolParameters {\n return FindStationsToolParametersSchema.parse(params);\n }\n\n /**\n * The timestamp of the evidence.\n */\n private evidenceTs: DateTime;\n\n constructor(evidenceTs: DateTime, repo: MRTDownRepository) {\n super();\n this.evidenceTs = evidenceTs;\n this.repo = repo;\n }\n\n public async runner(params: FindStationsToolParameters): Promise<string> {\n console.log('[findStations] Calling tool with parameters:', params);\n\n const stations = this.repo.stations.searchByName(params.stationNames);\n\n const table: Table = {\n type: 'table',\n children: [\n {\n type: 'tableRow',\n children: [\n {\n type: 'tableCell',\n children: [{ type: 'text', value: 'Station ID' }],\n },\n {\n type: 'tableCell',\n children: [{ type: 'text', value: 'Station Name' }],\n },\n {\n type: 'tableCell',\n children: [{ type: 'text', value: 'Station Codes' }],\n },\n {\n type: 'tableCell',\n children: [{ type: 'text', value: 'Line IDs' }],\n },\n ],\n },\n ],\n };\n\n for (const station of stations) {\n const relevantStationCodes = station.stationCodes.filter((membership) => {\n const startedAt = DateTime.fromISO(membership.startedAt);\n assert(startedAt.isValid, `Invalid date: ${membership.startedAt}`);\n if (startedAt > this.evidenceTs) return false;\n if (\n membership.endedAt != null &&\n DateTime.fromISO(membership.endedAt) < this.evidenceTs\n )\n return false;\n return true;\n });\n\n const stationCodesSet = new Set<string>(\n relevantStationCodes.map((membership) => membership.code),\n );\n\n const lineIds = relevantStationCodes.map(\n (membership) => membership.lineId,\n );\n\n table.children.push({\n type: 'tableRow',\n children: [\n {\n type: 'tableCell',\n children: [{ type: 'text', value: station.id }],\n },\n {\n type: 'tableCell',\n children: [{ type: 'text', value: station.name['en-SG'] }],\n },\n {\n type: 'tableCell',\n children: [\n {\n type: 'text',\n value: Array.from(stationCodesSet).join(', '),\n },\n ],\n },\n {\n type: 'tableCell',\n children: [\n {\n type: 'text',\n value: lineIds.join(', '),\n },\n ],\n },\n ],\n });\n }\n\n const output = toMarkdown(table, {\n extensions: [gfmToMarkdown()],\n });\n console.log(`[findStations] Response output:\\n${output}`);\n\n return output;\n }\n}\n"]}
@@ -1,14 +0,0 @@
1
- import { z } from 'zod';
2
- declare const ResponseSchema: z.ZodObject<{
3
- title: z.ZodString;
4
- slug: z.ZodString;
5
- }, z.core.$strip>;
6
- export type GenerateIssueTitleAndSlugParams = {
7
- text: string;
8
- };
9
- export type GenerateIssueTitleAndSlugResult = z.infer<typeof ResponseSchema>;
10
- /**
11
- * Generate a title and slug for the given text.
12
- */
13
- export declare function generateIssueTitleAndSlug(params: GenerateIssueTitleAndSlugParams): Promise<GenerateIssueTitleAndSlugResult>;
14
- export {};
@@ -1,38 +0,0 @@
1
- import { z } from 'zod';
2
- import { openAiClient } from '../../client.js';
3
- import { assert } from '../../../util/assert.js';
4
- import { buildSystemPrompt } from './prompt.js';
5
- const ResponseSchema = z.object({
6
- title: z.string(),
7
- slug: z.string(),
8
- });
9
- /**
10
- * Generate a title and slug for the given text.
11
- */
12
- export async function generateIssueTitleAndSlug(params) {
13
- const systemPrompt = buildSystemPrompt();
14
- const context = [
15
- {
16
- role: 'user',
17
- content: `
18
- Text: ${params.text}
19
- `.trim(),
20
- },
21
- ];
22
- const response = await openAiClient.responses.parse({
23
- model: 'gpt-5-nano',
24
- input: context,
25
- instructions: systemPrompt,
26
- text: {
27
- format: {
28
- type: 'json_schema',
29
- name: 'Response',
30
- strict: true,
31
- schema: z.toJSONSchema(ResponseSchema),
32
- },
33
- },
34
- });
35
- assert(response.output_parsed != null, 'Response output parsed is null');
36
- return response.output_parsed;
37
- }
38
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"/","sources":["llm/functions/generateIssueTitleAndSlug/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;CACjB,CAAC,CAAC;AAQH;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,MAAuC;IAEvC,MAAM,YAAY,GAAG,iBAAiB,EAAE,CAAC;IAEzC,MAAM,OAAO,GAAwB;QACnC;YACE,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE;QACP,MAAM,CAAC,IAAI;CAClB,CAAC,IAAI,EAAE;SACH;KACF,CAAC;IAEF,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,SAAS,CAAC,KAAK,CAAC;QAClD,KAAK,EAAE,YAAY;QACnB,KAAK,EAAE,OAAO;QACd,YAAY,EAAE,YAAY;QAC1B,IAAI,EAAE;YACJ,MAAM,EAAE;gBACN,IAAI,EAAE,aAAa;gBACnB,IAAI,EAAE,UAAU;gBAChB,MAAM,EAAE,IAAI;gBACZ,MAAM,EAAE,CAAC,CAAC,YAAY,CAAC,cAAc,CAAC;aACvC;SACF;KACF,CAAC,CAAC;IAEH,MAAM,CAAC,QAAQ,CAAC,aAAa,IAAI,IAAI,EAAE,gCAAgC,CAAC,CAAC;IAEzE,OAAO,QAAQ,CAAC,aAAa,CAAC;AAChC,CAAC","sourcesContent":["import type { ResponseInputItem } from 'openai/resources/responses/responses.mjs';\nimport { z } from 'zod';\nimport { openAiClient } from '../../client.js';\nimport { assert } from '../../../util/assert.js';\nimport { buildSystemPrompt } from './prompt.js';\n\nconst ResponseSchema = z.object({\n title: z.string(),\n slug: z.string(),\n});\n\nexport type GenerateIssueTitleAndSlugParams = {\n text: string;\n};\n\nexport type GenerateIssueTitleAndSlugResult = z.infer<typeof ResponseSchema>;\n\n/**\n * Generate a title and slug for the given text.\n */\nexport async function generateIssueTitleAndSlug(\n params: GenerateIssueTitleAndSlugParams,\n): Promise<GenerateIssueTitleAndSlugResult> {\n const systemPrompt = buildSystemPrompt();\n\n const context: ResponseInputItem[] = [\n {\n role: 'user',\n content: `\nText: ${params.text}\n`.trim(),\n },\n ];\n\n const response = await openAiClient.responses.parse({\n model: 'gpt-5-nano',\n input: context,\n instructions: systemPrompt,\n text: {\n format: {\n type: 'json_schema',\n name: 'Response',\n strict: true,\n schema: z.toJSONSchema(ResponseSchema),\n },\n },\n });\n\n assert(response.output_parsed != null, 'Response output parsed is null');\n\n return response.output_parsed;\n}\n"]}
@@ -1 +0,0 @@
1
- export declare function buildSystemPrompt(): string;
@@ -1,23 +0,0 @@
1
- export function buildSystemPrompt() {
2
- return `
3
- You are an AI assistant helping to process MRT/LRT incident data for Singapore's public transport system. Your task is to generate a clear title and URL slug for the given issue based on the provided text.
4
-
5
- ## Your Responsibilities
6
-
7
- ### 1. Title Creation
8
- - Create clear, factual titles describing the disruption, maintenance, or infrastructure issue
9
- - Format: "[Line Code] [Type of Issue] - [Location/Scope]" when line and scope are known
10
- - Examples: "NSL Signalling Fault - Ang Mo Kio to Bishan", "EWL Train Breakdown - Clementi Station", "Circle Line: Service disruption due to track fault"
11
- - Avoid sensational language; stick to facts
12
- - Use English (en-SG) as the output language
13
-
14
- ### 2. Slug Generation
15
- - Slug will be prefixed with YYYY-MM-DD by the system (e.g., "2024-01-15-nsl-signalling-fault")
16
- - Generate only the descriptive part (no date)
17
- - Rules: lowercase, hyphen-separated, no spaces, valid URL slug
18
- - Keep slugs concise but descriptive enough to distinguish similar issues
19
- - Include key identifiers: line, issue type, location or cause when relevant
20
- - Examples: "nsl-signalling-fault", "circle-line-track-fault-holland-village-caldecott", "faulty-cable-led-to-circle-line-disruption"
21
- `.trim();
22
- }
23
- //# sourceMappingURL=prompt.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"prompt.js","sourceRoot":"/","sources":["llm/functions/generateIssueTitleAndSlug/prompt.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,iBAAiB;IAC/B,OAAO;;;;;;;;;;;;;;;;;;;CAmBR,CAAC,IAAI,EAAE,CAAC;AACT,CAAC","sourcesContent":["export function buildSystemPrompt() {\n return `\nYou are an AI assistant helping to process MRT/LRT incident data for Singapore's public transport system. Your task is to generate a clear title and URL slug for the given issue based on the provided text.\n\n## Your Responsibilities\n\n### 1. Title Creation\n- Create clear, factual titles describing the disruption, maintenance, or infrastructure issue\n- Format: \"[Line Code] [Type of Issue] - [Location/Scope]\" when line and scope are known\n- Examples: \"NSL Signalling Fault - Ang Mo Kio to Bishan\", \"EWL Train Breakdown - Clementi Station\", \"Circle Line: Service disruption due to track fault\"\n- Avoid sensational language; stick to facts\n- Use English (en-SG) as the output language\n\n### 2. Slug Generation\n- Slug will be prefixed with YYYY-MM-DD by the system (e.g., \"2024-01-15-nsl-signalling-fault\")\n- Generate only the descriptive part (no date)\n- Rules: lowercase, hyphen-separated, no spaces, valid URL slug\n- Keep slugs concise but descriptive enough to distinguish similar issues\n- Include key identifiers: line, issue type, location or cause when relevant\n- Examples: \"nsl-signalling-fault\", \"circle-line-track-fault-holland-village-caldecott\", \"faulty-cable-led-to-circle-line-disruption\"\n`.trim();\n}\n"]}
@@ -1 +0,0 @@
1
- export declare function translate(text: string): Promise<never>;
@@ -1,59 +0,0 @@
1
- import { z } from 'zod';
2
- import { estimateOpenAICostFromUsage, normalizeOpenAIResponsesUsage, } from '../../../helpers/estimateOpenAICost.js';
3
- import { openAiClient } from '../../client.js';
4
- import { TranslationsSchema } from '../../../schema/common.js';
5
- import { assert } from '../../../util/assert.js';
6
- export async function translate(text) {
7
- console.log('[translate] Translating text:', text);
8
- const model = 'gpt-5-nano';
9
- const context = [{ role: 'user', content: text }];
10
- const response = await openAiClient.responses.parse({
11
- model,
12
- input: context,
13
- instructions: `You are a helpful assistant that translates text to the following languages:
14
- - English
15
- - Chinese (Simplified)
16
- - Malay
17
- - Tamil
18
-
19
- These translations relate to transit disruption/maintenance/infrastructure issues and can contain names of lines and/or stations.
20
- Keep the names in English as much as possible, do not provide any translations for them.
21
- `.trim(),
22
- text: {
23
- format: {
24
- type: 'json_schema',
25
- name: 'Translation',
26
- strict: true,
27
- schema: z.toJSONSchema(TranslationsSchema),
28
- },
29
- },
30
- reasoning: {
31
- effort: 'minimal',
32
- summary: 'concise',
33
- },
34
- store: false,
35
- include: ['reasoning.encrypted_content'],
36
- });
37
- const usage = normalizeOpenAIResponsesUsage(response.usage);
38
- const estimate = estimateOpenAICostFromUsage({ model, usage });
39
- if (usage != null) {
40
- console.log('[translate] Usage:', {
41
- inputTokens: usage.inputTokens,
42
- cachedInputTokens: usage.cachedInputTokens,
43
- outputTokens: usage.outputTokens,
44
- totalTokens: usage.totalTokens,
45
- });
46
- if (estimate != null) {
47
- console.log('[translate] Estimated cost (USD):', estimate.estimatedCostUsd.toFixed(8));
48
- }
49
- else {
50
- console.log(`[translate] No pricing configured for model "${model}".`);
51
- }
52
- }
53
- else {
54
- console.log('[translate] Usage is unavailable');
55
- }
56
- assert(response.output_parsed != null, 'Response output parsed is null');
57
- return response.output_parsed;
58
- }
59
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"/","sources":["llm/functions/translate/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACL,2BAA2B,EAC3B,6BAA6B,GAC9B,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEjD,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAY;IAC1C,OAAO,CAAC,GAAG,CAAC,+BAA+B,EAAE,IAAI,CAAC,CAAC;IACnD,MAAM,KAAK,GAAG,YAAY,CAAC;IAE3B,MAAM,OAAO,GAAwB,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IAEvE,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,SAAS,CAAC,KAAK,CAAC;QAClD,KAAK;QACL,KAAK,EAAE,OAAO;QACd,YAAY,EACV;;;;;;;;CAQL,CAAC,IAAI,EAAE;QACJ,IAAI,EAAE;YACJ,MAAM,EAAE;gBACN,IAAI,EAAE,aAAa;gBACnB,IAAI,EAAE,aAAa;gBACnB,MAAM,EAAE,IAAI;gBACZ,MAAM,EAAE,CAAC,CAAC,YAAY,CAAC,kBAAkB,CAAC;aAC3C;SACF;QACD,SAAS,EAAE;YACT,MAAM,EAAE,SAAS;YACjB,OAAO,EAAE,SAAS;SACnB;QACD,KAAK,EAAE,KAAK;QACZ,OAAO,EAAE,CAAC,6BAA6B,CAAC;KACzC,CAAC,CAAC;IAEH,MAAM,KAAK,GAAG,6BAA6B,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC5D,MAAM,QAAQ,GAAG,2BAA2B,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/D,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;QAClB,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAAE;YAChC,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;YAC1C,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,WAAW,EAAE,KAAK,CAAC,WAAW;SAC/B,CAAC,CAAC;QACH,IAAI,QAAQ,IAAI,IAAI,EAAE,CAAC;YACrB,OAAO,CAAC,GAAG,CACT,mCAAmC,EACnC,QAAQ,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,CACrC,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,gDAAgD,KAAK,IAAI,CAAC,CAAC;QACzE,CAAC;IACH,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;IAClD,CAAC;IAED,MAAM,CAAC,QAAQ,CAAC,aAAa,IAAI,IAAI,EAAE,gCAAgC,CAAC,CAAC;IAEzE,OAAO,QAAQ,CAAC,aAAa,CAAC;AAChC,CAAC","sourcesContent":["import type { ResponseInputItem } from 'openai/resources/responses/responses.js';\nimport { z } from 'zod';\nimport {\n estimateOpenAICostFromUsage,\n normalizeOpenAIResponsesUsage,\n} from '../../../helpers/estimateOpenAICost.js';\nimport { openAiClient } from '../../client.js';\nimport { TranslationsSchema } from '../../../schema/common.js';\nimport { assert } from '../../../util/assert.js';\n\nexport async function translate(text: string) {\n console.log('[translate] Translating text:', text);\n const model = 'gpt-5-nano';\n\n const context: ResponseInputItem[] = [{ role: 'user', content: text }];\n\n const response = await openAiClient.responses.parse({\n model,\n input: context,\n instructions:\n `You are a helpful assistant that translates text to the following languages:\n- English\n- Chinese (Simplified)\n- Malay\n- Tamil\n\nThese translations relate to transit disruption/maintenance/infrastructure issues and can contain names of lines and/or stations.\nKeep the names in English as much as possible, do not provide any translations for them.\n`.trim(),\n text: {\n format: {\n type: 'json_schema',\n name: 'Translation',\n strict: true,\n schema: z.toJSONSchema(TranslationsSchema),\n },\n },\n reasoning: {\n effort: 'minimal',\n summary: 'concise',\n },\n store: false,\n include: ['reasoning.encrypted_content'],\n });\n\n const usage = normalizeOpenAIResponsesUsage(response.usage);\n const estimate = estimateOpenAICostFromUsage({ model, usage });\n if (usage != null) {\n console.log('[translate] Usage:', {\n inputTokens: usage.inputTokens,\n cachedInputTokens: usage.cachedInputTokens,\n outputTokens: usage.outputTokens,\n totalTokens: usage.totalTokens,\n });\n if (estimate != null) {\n console.log(\n '[translate] Estimated cost (USD):',\n estimate.estimatedCostUsd.toFixed(8),\n );\n } else {\n console.log(`[translate] No pricing configured for model \"${model}\".`);\n }\n } else {\n console.log('[translate] Usage is unavailable');\n }\n\n assert(response.output_parsed != null, 'Response output parsed is null');\n\n return response.output_parsed;\n}\n"]}
@@ -1 +0,0 @@
1
- import 'dotenv/config';
@@ -1,139 +0,0 @@
1
- import 'dotenv/config';
2
- import { resolve } from 'node:path';
3
- import { describe } from 'vitest';
4
- import { describeEval, StructuredOutputScorer } from 'vitest-evals';
5
- import { FileStore } from '../../../repo/common/FileStore.js';
6
- import { MRTDownRepository } from '../../../repo/MRTDownRepository.js';
7
- import { triageNewEvidence, } from './index.js';
8
- describe('triageNewEvidence', () => {
9
- describeEval('should triage the new evidence into an existing issue or a new issue', {
10
- // @ts-expect-error input is a string in the vitest-evals library
11
- async data() {
12
- const store = new FileStore(resolve(import.meta.dirname, '../../fixtures/data'));
13
- const repo = new MRTDownRepository({ store });
14
- return [
15
- {
16
- input: {
17
- newEvidence: {
18
- ts: '2026-01-01T07:10:00+08:00',
19
- text: '[TGL] Due to a track fault at Tengah, train services on the Tengah Line are delayed between Bukit Batok and Bukit Merah Central',
20
- },
21
- repo,
22
- // This is used by vitest-evals as the test name, as the library expects `input` to be a string.
23
- toString() {
24
- return '[DISRUPTION] Related to an existing issue';
25
- },
26
- },
27
- expected: {
28
- result: {
29
- kind: 'part-of-existing-issue',
30
- issueId: '2026-01-01-tgl-train-fault',
31
- },
32
- },
33
- },
34
- {
35
- input: {
36
- newEvidence: {
37
- ts: '2026-01-01T07:10:00+08:00',
38
- text: '[TGL] Due to a track fault at Tengah, train services on the Tengah Line are delayed between Bukit Merah Central and Outram Park',
39
- },
40
- repo,
41
- // This is used by vitest-evals as the test name, as the library expects `input` to be a string.
42
- toString() {
43
- return '[DISRUPTION] Related to a new issue on a different part of the same line';
44
- },
45
- },
46
- expected: {
47
- result: {
48
- kind: 'part-of-new-issue',
49
- issueType: 'disruption',
50
- },
51
- },
52
- },
53
- {
54
- input: {
55
- newEvidence: {
56
- ts: '2026-01-01T07:10:00+08:00',
57
- text: '[TGL] Due to maintenance works, services on the Tengah Line will end earlier at 11pm tonight.',
58
- },
59
- repo,
60
- // This is used by vitest-evals as the test name, as the library expects `input` to be a string.
61
- toString() {
62
- return '[MAINTENANCE] Related to a new issue';
63
- },
64
- },
65
- expected: {
66
- result: {
67
- kind: 'part-of-new-issue',
68
- issueType: 'maintenance',
69
- },
70
- },
71
- },
72
- {
73
- input: {
74
- newEvidence: {
75
- ts: '2026-03-01T07:10:00+08:00',
76
- text: '[SLL] Due to a track fault at Seletar, train services on the Seletar Line are delayed between Seletar Aerospace and Bukit Merah Central',
77
- },
78
- repo: new MRTDownRepository({
79
- store: new FileStore(resolve(import.meta.dirname, '../fixtures/data')),
80
- }),
81
- // This is used by vitest-evals as the test name, as the library expects `input` to be a string.
82
- toString() {
83
- return '[DISRUPTION] Related to a new issue';
84
- },
85
- },
86
- expected: {
87
- result: {
88
- kind: 'part-of-new-issue',
89
- issueType: 'disruption',
90
- },
91
- },
92
- },
93
- {
94
- input: {
95
- newEvidence: {
96
- ts: '2026-03-01T07:10:00+08:00',
97
- text: '[SLL] MRT Platform screen doors at Seletar Line stations will undergo renewal works from 1st March to 31st March 2026.',
98
- },
99
- repo,
100
- // This is used by vitest-evals as the test name, as the library expects `input` to be a string.
101
- toString() {
102
- return '[INFRA] Related to a new issue';
103
- },
104
- },
105
- expected: {
106
- result: {
107
- kind: 'part-of-new-issue',
108
- issueType: 'infra',
109
- },
110
- },
111
- },
112
- {
113
- input: {
114
- newEvidence: {
115
- ts: '2026-03-01T07:10:00+08:00',
116
- text: "Singapore's MRT system is the best in the world.",
117
- },
118
- repo,
119
- // This is used by vitest-evals as the test name, as the library expects `input` to be a string.
120
- toString() {
121
- return 'Irrelevant content';
122
- },
123
- },
124
- expected: {
125
- result: {
126
- kind: 'irrelevant-content',
127
- },
128
- },
129
- },
130
- ];
131
- },
132
- async task(input) {
133
- const result = await triageNewEvidence(input);
134
- return JSON.stringify(result);
135
- },
136
- scorers: [StructuredOutputScorer()],
137
- });
138
- });
139
- //# sourceMappingURL=eval.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"eval.test.js","sourceRoot":"/","sources":["llm/functions/triageNewEvidence/eval.test.ts"],"names":[],"mappings":"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","sourcesContent":["import 'dotenv/config';\n\nimport { resolve } from 'node:path';\nimport { describe } from 'vitest';\nimport { describeEval, StructuredOutputScorer } from 'vitest-evals';\nimport { FileStore } from '../../../repo/common/FileStore.js';\nimport { MRTDownRepository } from '../../../repo/MRTDownRepository.js';\nimport {\n type TriageNewEvidenceParams,\n type TriageNewEvidenceResult,\n triageNewEvidence,\n} from './index.js';\n\ndescribe('triageNewEvidence', () => {\n describeEval(\n 'should triage the new evidence into an existing issue or a new issue',\n {\n // @ts-expect-error input is a string in the vitest-evals library\n async data() {\n const store = new FileStore(\n resolve(import.meta.dirname, '../../fixtures/data'),\n );\n const repo = new MRTDownRepository({ store });\n\n return [\n {\n input: {\n newEvidence: {\n ts: '2026-01-01T07:10:00+08:00',\n text: '[TGL] Due to a track fault at Tengah, train services on the Tengah Line are delayed between Bukit Batok and Bukit Merah Central',\n },\n repo,\n // This is used by vitest-evals as the test name, as the library expects `input` to be a string.\n toString() {\n return '[DISRUPTION] Related to an existing issue';\n },\n },\n expected: {\n result: {\n kind: 'part-of-existing-issue',\n issueId: '2026-01-01-tgl-train-fault',\n },\n },\n },\n {\n input: {\n newEvidence: {\n ts: '2026-01-01T07:10:00+08:00',\n text: '[TGL] Due to a track fault at Tengah, train services on the Tengah Line are delayed between Bukit Merah Central and Outram Park',\n },\n repo,\n // This is used by vitest-evals as the test name, as the library expects `input` to be a string.\n toString() {\n return '[DISRUPTION] Related to a new issue on a different part of the same line';\n },\n },\n expected: {\n result: {\n kind: 'part-of-new-issue',\n issueType: 'disruption',\n },\n },\n },\n {\n input: {\n newEvidence: {\n ts: '2026-01-01T07:10:00+08:00',\n text: '[TGL] Due to maintenance works, services on the Tengah Line will end earlier at 11pm tonight.',\n },\n repo,\n // This is used by vitest-evals as the test name, as the library expects `input` to be a string.\n toString() {\n return '[MAINTENANCE] Related to a new issue';\n },\n },\n expected: {\n result: {\n kind: 'part-of-new-issue',\n issueType: 'maintenance',\n },\n },\n },\n {\n input: {\n newEvidence: {\n ts: '2026-03-01T07:10:00+08:00',\n text: '[SLL] Due to a track fault at Seletar, train services on the Seletar Line are delayed between Seletar Aerospace and Bukit Merah Central',\n },\n repo: new MRTDownRepository({\n store: new FileStore(\n resolve(import.meta.dirname, '../fixtures/data'),\n ),\n }),\n // This is used by vitest-evals as the test name, as the library expects `input` to be a string.\n toString() {\n return '[DISRUPTION] Related to a new issue';\n },\n },\n expected: {\n result: {\n kind: 'part-of-new-issue',\n issueType: 'disruption',\n },\n },\n },\n {\n input: {\n newEvidence: {\n ts: '2026-03-01T07:10:00+08:00',\n text: '[SLL] MRT Platform screen doors at Seletar Line stations will undergo renewal works from 1st March to 31st March 2026.',\n },\n repo,\n // This is used by vitest-evals as the test name, as the library expects `input` to be a string.\n toString() {\n return '[INFRA] Related to a new issue';\n },\n },\n expected: {\n result: {\n kind: 'part-of-new-issue',\n issueType: 'infra',\n },\n },\n },\n {\n input: {\n newEvidence: {\n ts: '2026-03-01T07:10:00+08:00',\n text: \"Singapore's MRT system is the best in the world.\",\n },\n repo,\n // This is used by vitest-evals as the test name, as the library expects `input` to be a string.\n toString() {\n return 'Irrelevant content';\n },\n },\n expected: {\n result: {\n kind: 'irrelevant-content',\n },\n },\n },\n ] satisfies {\n input: TriageNewEvidenceParams & { toString(): string };\n expected: TriageNewEvidenceResult;\n }[];\n },\n async task(input) {\n const result = await triageNewEvidence(\n input as unknown as TriageNewEvidenceParams,\n );\n return JSON.stringify(result);\n },\n scorers: [StructuredOutputScorer()],\n },\n );\n});\n"]}
@@ -1,37 +0,0 @@
1
- import z from 'zod';
2
- import type { MRTDownRepository } from '../../../repo/MRTDownRepository.js';
3
- declare const ResponseSchema: z.ZodObject<{
4
- result: z.ZodDiscriminatedUnion<[z.ZodObject<{
5
- kind: z.ZodLiteral<"part-of-existing-issue">;
6
- issueId: z.ZodString;
7
- }, z.z.core.$strip>, z.ZodObject<{
8
- kind: z.ZodLiteral<"part-of-new-issue">;
9
- issueType: z.ZodEnum<{
10
- disruption: "disruption";
11
- maintenance: "maintenance";
12
- infra: "infra";
13
- }>;
14
- }, z.z.core.$strip>, z.ZodObject<{
15
- kind: z.ZodLiteral<"irrelevant-content">;
16
- }, z.z.core.$strip>]>;
17
- }, z.z.core.$strip>;
18
- export type TriageNewEvidenceParams = {
19
- newEvidence: {
20
- ts: string;
21
- text: string;
22
- };
23
- repo: MRTDownRepository;
24
- };
25
- export type TriageNewEvidenceResult = z.infer<typeof ResponseSchema>;
26
- export declare function triageNewEvidence(params: TriageNewEvidenceParams): Promise<{
27
- result: {
28
- kind: "part-of-existing-issue";
29
- issueId: string;
30
- } | {
31
- kind: "part-of-new-issue";
32
- issueType: "disruption" | "maintenance" | "infra";
33
- } | {
34
- kind: "irrelevant-content";
35
- };
36
- }>;
37
- export {};
@@ -1,121 +0,0 @@
1
- import { DateTime } from 'luxon';
2
- import z from 'zod';
3
- import { openAiClient } from '../../client.js';
4
- import { IssueIdSchema } from '../../../schema/issue/id.js';
5
- import { IssueTypeSchema } from '../../../schema/issue/issueType.js';
6
- import { assert } from '../../../util/assert.js';
7
- import { buildSystemPrompt } from './prompt.js';
8
- import { FindIssuesTool } from './tools/FindIssuesTool.js';
9
- import { GetIssueTool } from './tools/GetIssueTool.js';
10
- const TOOL_CALL_LIMIT = 5;
11
- const ResponseSchema = z.object({
12
- result: z.discriminatedUnion('type', [
13
- z.object({
14
- kind: z.literal('part-of-existing-issue'),
15
- issueId: IssueIdSchema,
16
- }),
17
- z.object({
18
- kind: z.literal('part-of-new-issue'),
19
- issueType: IssueTypeSchema,
20
- }),
21
- z.object({
22
- kind: z.literal('irrelevant-content'),
23
- }),
24
- ]),
25
- });
26
- export async function triageNewEvidence(params) {
27
- const evidenceTs = DateTime.fromISO(params.newEvidence.ts);
28
- assert(evidenceTs.isValid, `Invalid date: ${params.newEvidence.ts}`);
29
- const findIssuesTool = new FindIssuesTool(params.repo);
30
- const getIssueTool = new GetIssueTool(params.repo);
31
- const toolRegistry = {
32
- [findIssuesTool.name]: findIssuesTool,
33
- [getIssueTool.name]: getIssueTool,
34
- };
35
- const systemPrompt = buildSystemPrompt();
36
- const context = [
37
- {
38
- role: 'user',
39
- content: `
40
- Evidence: ${params.newEvidence.text}
41
-
42
- Timestamp: ${evidenceTs.toISO({ includeOffset: true })}
43
- `.trim(),
44
- },
45
- ];
46
- let toolCallCount = 0;
47
- let response;
48
- do {
49
- response = await openAiClient.responses.parse({
50
- model: 'gpt-5-mini',
51
- input: context,
52
- instructions: systemPrompt,
53
- text: {
54
- format: {
55
- type: 'json_schema',
56
- name: 'Response',
57
- strict: true,
58
- schema: z.toJSONSchema(ResponseSchema),
59
- },
60
- },
61
- tools: Object.values(toolRegistry).map((tool) => {
62
- return {
63
- type: 'function',
64
- name: tool.name,
65
- description: tool.description,
66
- parameters: tool.paramsSchema,
67
- strict: true,
68
- };
69
- }),
70
- // Don't persist conversation with OpenAI, but include reasoning content to
71
- // continue the thread with the same reasoning.
72
- store: false,
73
- include: ['reasoning.encrypted_content'],
74
- });
75
- for (const item of response.output) {
76
- switch (item.type) {
77
- case 'function_call': {
78
- /**
79
- * Prevent the `parsed_arguments` field from being included
80
- * https://github.com/openai/openai-python/issues/2374
81
- */
82
- context.push({
83
- type: 'function_call',
84
- id: item.id,
85
- call_id: item.call_id,
86
- name: item.name,
87
- arguments: item.arguments,
88
- });
89
- if (toolCallCount > TOOL_CALL_LIMIT) {
90
- context.push({
91
- type: 'function_call_output',
92
- call_id: item.call_id,
93
- output: 'Ran out of tool calls. Stop Calling.',
94
- });
95
- console.log('Forced short-circuit, returning error message in tool call result.');
96
- }
97
- if (item.name in toolRegistry) {
98
- const tool = toolRegistry[item.name];
99
- const params = tool.parseParams(JSON.parse(item.arguments));
100
- // Call the tool's run function
101
- const result = await tool.runner(params);
102
- context.push({
103
- type: 'function_call_output',
104
- call_id: item.call_id,
105
- output: result,
106
- });
107
- }
108
- toolCallCount++;
109
- break;
110
- }
111
- default: {
112
- context.push(item);
113
- break;
114
- }
115
- }
116
- }
117
- } while (response.output.some((item) => item.type === 'function_call'));
118
- assert(response.output_parsed != null, 'Response output parsed is null');
119
- return response.output_parsed;
120
- }
121
- //# sourceMappingURL=index.js.map