@alextis59/athena 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +147 -0
  3. package/dist/agent/ask.d.ts +7 -0
  4. package/dist/agent/ask.d.ts.map +1 -0
  5. package/dist/agent/ask.js +35 -0
  6. package/dist/agent/ask.js.map +1 -0
  7. package/dist/agent/citations.d.ts +27 -0
  8. package/dist/agent/citations.d.ts.map +1 -0
  9. package/dist/agent/citations.js +190 -0
  10. package/dist/agent/citations.js.map +1 -0
  11. package/dist/agent/fake-provider.d.ts +9 -0
  12. package/dist/agent/fake-provider.d.ts.map +1 -0
  13. package/dist/agent/fake-provider.js +51 -0
  14. package/dist/agent/fake-provider.js.map +1 -0
  15. package/dist/agent/index.d.ts +10 -0
  16. package/dist/agent/index.d.ts.map +1 -0
  17. package/dist/agent/index.js +6 -0
  18. package/dist/agent/index.js.map +1 -0
  19. package/dist/agent/loop.d.ts +11 -0
  20. package/dist/agent/loop.d.ts.map +1 -0
  21. package/dist/agent/loop.js +156 -0
  22. package/dist/agent/loop.js.map +1 -0
  23. package/dist/agent/providers.d.ts +17 -0
  24. package/dist/agent/providers.d.ts.map +1 -0
  25. package/dist/agent/providers.js +171 -0
  26. package/dist/agent/providers.js.map +1 -0
  27. package/dist/agent/tools.d.ts +8 -0
  28. package/dist/agent/tools.d.ts.map +1 -0
  29. package/dist/agent/tools.js +233 -0
  30. package/dist/agent/tools.js.map +1 -0
  31. package/dist/agent/types.d.ts +84 -0
  32. package/dist/agent/types.d.ts.map +1 -0
  33. package/dist/agent/types.js +2 -0
  34. package/dist/agent/types.js.map +1 -0
  35. package/dist/cli/help.d.ts +2 -0
  36. package/dist/cli/help.d.ts.map +1 -0
  37. package/dist/cli/help.js +28 -0
  38. package/dist/cli/help.js.map +1 -0
  39. package/dist/cli/main.d.ts +3 -0
  40. package/dist/cli/main.d.ts.map +1 -0
  41. package/dist/cli/main.js +5 -0
  42. package/dist/cli/main.js.map +1 -0
  43. package/dist/cli/options.d.ts +21 -0
  44. package/dist/cli/options.d.ts.map +1 -0
  45. package/dist/cli/options.js +97 -0
  46. package/dist/cli/options.js.map +1 -0
  47. package/dist/cli/run.d.ts +21 -0
  48. package/dist/cli/run.d.ts.map +1 -0
  49. package/dist/cli/run.js +144 -0
  50. package/dist/cli/run.js.map +1 -0
  51. package/dist/config/index.d.ts +4 -0
  52. package/dist/config/index.d.ts.map +1 -0
  53. package/dist/config/index.js +3 -0
  54. package/dist/config/index.js.map +1 -0
  55. package/dist/config/loader.d.ts +14 -0
  56. package/dist/config/loader.d.ts.map +1 -0
  57. package/dist/config/loader.js +352 -0
  58. package/dist/config/loader.js.map +1 -0
  59. package/dist/config/schema.d.ts +6 -0
  60. package/dist/config/schema.d.ts.map +1 -0
  61. package/dist/config/schema.js +72 -0
  62. package/dist/config/schema.js.map +1 -0
  63. package/dist/config/types.d.ts +53 -0
  64. package/dist/config/types.d.ts.map +1 -0
  65. package/dist/config/types.js +2 -0
  66. package/dist/config/types.js.map +1 -0
  67. package/dist/doctor/doctor.d.ts +47 -0
  68. package/dist/doctor/doctor.d.ts.map +1 -0
  69. package/dist/doctor/doctor.js +159 -0
  70. package/dist/doctor/doctor.js.map +1 -0
  71. package/dist/embeddings/index.d.ts +117 -0
  72. package/dist/embeddings/index.d.ts.map +1 -0
  73. package/dist/embeddings/index.js +515 -0
  74. package/dist/embeddings/index.js.map +1 -0
  75. package/dist/errors.d.ts +19 -0
  76. package/dist/errors.d.ts.map +1 -0
  77. package/dist/errors.js +37 -0
  78. package/dist/errors.js.map +1 -0
  79. package/dist/index.d.ts +17 -0
  80. package/dist/index.d.ts.map +1 -0
  81. package/dist/index.js +9 -0
  82. package/dist/index.js.map +1 -0
  83. package/dist/indexer/discovery.d.ts +10 -0
  84. package/dist/indexer/discovery.d.ts.map +1 -0
  85. package/dist/indexer/discovery.js +38 -0
  86. package/dist/indexer/discovery.js.map +1 -0
  87. package/dist/indexer/hash.d.ts +3 -0
  88. package/dist/indexer/hash.d.ts.map +1 -0
  89. package/dist/indexer/hash.js +11 -0
  90. package/dist/indexer/hash.js.map +1 -0
  91. package/dist/indexer/index.d.ts +7 -0
  92. package/dist/indexer/index.d.ts.map +1 -0
  93. package/dist/indexer/index.js +5 -0
  94. package/dist/indexer/index.js.map +1 -0
  95. package/dist/indexer/kinds.d.ts +4 -0
  96. package/dist/indexer/kinds.d.ts.map +1 -0
  97. package/dist/indexer/kinds.js +38 -0
  98. package/dist/indexer/kinds.js.map +1 -0
  99. package/dist/indexer/run.d.ts +42 -0
  100. package/dist/indexer/run.d.ts.map +1 -0
  101. package/dist/indexer/run.js +563 -0
  102. package/dist/indexer/run.js.map +1 -0
  103. package/dist/logging/logger.d.ts +11 -0
  104. package/dist/logging/logger.d.ts.map +1 -0
  105. package/dist/logging/logger.js +18 -0
  106. package/dist/logging/logger.js.map +1 -0
  107. package/dist/mcp/index.d.ts +35 -0
  108. package/dist/mcp/index.d.ts.map +1 -0
  109. package/dist/mcp/index.js +392 -0
  110. package/dist/mcp/index.js.map +1 -0
  111. package/dist/parsers/chunking.d.ts +4 -0
  112. package/dist/parsers/chunking.d.ts.map +1 -0
  113. package/dist/parsers/chunking.js +112 -0
  114. package/dist/parsers/chunking.js.map +1 -0
  115. package/dist/parsers/index.d.ts +8 -0
  116. package/dist/parsers/index.d.ts.map +1 -0
  117. package/dist/parsers/index.js +5 -0
  118. package/dist/parsers/index.js.map +1 -0
  119. package/dist/parsers/line-parser.d.ts +13 -0
  120. package/dist/parsers/line-parser.d.ts.map +1 -0
  121. package/dist/parsers/line-parser.js +242 -0
  122. package/dist/parsers/line-parser.js.map +1 -0
  123. package/dist/parsers/normalize.d.ts +4 -0
  124. package/dist/parsers/normalize.d.ts.map +1 -0
  125. package/dist/parsers/normalize.js +17 -0
  126. package/dist/parsers/normalize.js.map +1 -0
  127. package/dist/parsers/parser.d.ts +14 -0
  128. package/dist/parsers/parser.d.ts.map +1 -0
  129. package/dist/parsers/parser.js +77 -0
  130. package/dist/parsers/parser.js.map +1 -0
  131. package/dist/parsers/pdf2llm.d.ts +14 -0
  132. package/dist/parsers/pdf2llm.d.ts.map +1 -0
  133. package/dist/parsers/pdf2llm.js +215 -0
  134. package/dist/parsers/pdf2llm.js.map +1 -0
  135. package/dist/parsers/types.d.ts +48 -0
  136. package/dist/parsers/types.d.ts.map +1 -0
  137. package/dist/parsers/types.js +2 -0
  138. package/dist/parsers/types.js.map +1 -0
  139. package/dist/retrieval/index.d.ts +4 -0
  140. package/dist/retrieval/index.d.ts.map +1 -0
  141. package/dist/retrieval/index.js +3 -0
  142. package/dist/retrieval/index.js.map +1 -0
  143. package/dist/retrieval/schemas.d.ts +127 -0
  144. package/dist/retrieval/schemas.d.ts.map +1 -0
  145. package/dist/retrieval/schemas.js +65 -0
  146. package/dist/retrieval/schemas.js.map +1 -0
  147. package/dist/retrieval/tools.d.ts +31 -0
  148. package/dist/retrieval/tools.d.ts.map +1 -0
  149. package/dist/retrieval/tools.js +803 -0
  150. package/dist/retrieval/tools.js.map +1 -0
  151. package/dist/retrieval/types.d.ts +104 -0
  152. package/dist/retrieval/types.d.ts.map +1 -0
  153. package/dist/retrieval/types.js +2 -0
  154. package/dist/retrieval/types.js.map +1 -0
  155. package/dist/server/index.d.ts +3 -0
  156. package/dist/server/index.d.ts.map +1 -0
  157. package/dist/server/index.js +2 -0
  158. package/dist/server/index.js.map +1 -0
  159. package/dist/server/server.d.ts +49 -0
  160. package/dist/server/server.d.ts.map +1 -0
  161. package/dist/server/server.js +517 -0
  162. package/dist/server/server.js.map +1 -0
  163. package/dist/shared/types.d.ts +98 -0
  164. package/dist/shared/types.d.ts.map +1 -0
  165. package/dist/shared/types.js +2 -0
  166. package/dist/shared/types.js.map +1 -0
  167. package/dist/storage/database.d.ts +18 -0
  168. package/dist/storage/database.d.ts.map +1 -0
  169. package/dist/storage/database.js +66 -0
  170. package/dist/storage/database.js.map +1 -0
  171. package/dist/storage/index.d.ts +8 -0
  172. package/dist/storage/index.d.ts.map +1 -0
  173. package/dist/storage/index.js +5 -0
  174. package/dist/storage/index.js.map +1 -0
  175. package/dist/storage/migrations.d.ts +15 -0
  176. package/dist/storage/migrations.d.ts.map +1 -0
  177. package/dist/storage/migrations.js +170 -0
  178. package/dist/storage/migrations.js.map +1 -0
  179. package/dist/storage/paths.d.ts +15 -0
  180. package/dist/storage/paths.d.ts.map +1 -0
  181. package/dist/storage/paths.js +27 -0
  182. package/dist/storage/paths.js.map +1 -0
  183. package/dist/storage/schema.d.ts +11 -0
  184. package/dist/storage/schema.d.ts.map +1 -0
  185. package/dist/storage/schema.js +40 -0
  186. package/dist/storage/schema.js.map +1 -0
  187. package/dist/ui/index.d.ts +2 -0
  188. package/dist/ui/index.d.ts.map +1 -0
  189. package/dist/ui/index.js +2 -0
  190. package/dist/ui/index.js.map +1 -0
  191. package/dist/ui/static-app.d.ts +2 -0
  192. package/dist/ui/static-app.d.ts.map +1 -0
  193. package/dist/ui/static-app.js +735 -0
  194. package/dist/ui/static-app.js.map +1 -0
  195. package/docs/adr/0001-sqlite-driver.md +23 -0
  196. package/docs/agentic-rag-specifications.md +659 -0
  197. package/docs/agentic-rag-study.md +1056 -0
  198. package/docs/implementation-plan.md +1425 -0
  199. package/docs/mcp-integration.md +154 -0
  200. package/docs/validation-corpus.md +71 -0
  201. package/package.json +79 -0
package/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2026 Athena contributors
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
11
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
14
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15
+ PERFORMANCE OF THIS SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,147 @@
1
+ # Athena
2
+
3
+ Athena is a local-first documentation RAG command for project folders. It
4
+ indexes Markdown, MDX, text, RST, AsciiDoc, HTML, extensionless documentation,
5
+ and PDFs into a local `.athena/index.sqlite` cache, then exposes search, source
6
+ reading, cited terminal answers, a local web UI, and an optional read-only MCP
7
+ bridge for external coding agents.
8
+
9
+ The installed command is `athena`. The npm package is published as
10
+ `@alextis59/athena` because the unscoped `athena` package name is already taken
11
+ on npm.
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ npm install -g @alextis59/athena
17
+ ```
18
+
19
+ For ad hoc use inside a documentation folder:
20
+
21
+ ```bash
22
+ npx @alextis59/athena
23
+ ```
24
+
25
+ For development from this checkout:
26
+
27
+ ```bash
28
+ npm install
29
+ npm run build
30
+ npm link
31
+ athena --help
32
+ ```
33
+
34
+ ## Commands
35
+
36
+ ```bash
37
+ athena # build or update the local index, then start the UI
38
+ athena index # build or update .athena/index.sqlite only
39
+ athena serve # serve an existing index
40
+ athena serve --build # build first, then serve
41
+ athena ask "..." # one-shot terminal answer with citations
42
+ athena doctor # inspect config, index, parser, embedding, and port state
43
+ athena mcp # stdio MCP server for external coding agents
44
+ ```
45
+
46
+ Common options:
47
+
48
+ ```bash
49
+ --root <path> Project root to inspect
50
+ --config <path> Explicit athena.config.ts, .mjs, or .json file
51
+ --db <path> SQLite index path
52
+ --host <host> Server bind host
53
+ --port <port> Server port
54
+ --debug Enable debug logs
55
+ --json Emit machine-readable output where supported
56
+ ```
57
+
58
+ ## Local-First Defaults
59
+
60
+ Athena keeps private documentation local by default.
61
+
62
+ - The runtime cache lives in `.athena/`.
63
+ - The default embedding provider is local Transformers.js with
64
+ `mixedbread-ai/mxbai-embed-xsmall-v1`.
65
+ - PDF ingestion uses the published `pdf-2-llm` package.
66
+ - Athena owns its agent loop; no SDK controls tool selection, step limits,
67
+ memory, or citation validation.
68
+ - Remote embedding or chat providers require explicit configuration before
69
+ document text can leave the machine.
70
+
71
+ ## Configuration
72
+
73
+ Athena discovers `athena.config.ts`, `athena.config.mjs`, or
74
+ `athena.config.json` from the project root.
75
+
76
+ ```ts
77
+ import { defineConfig } from "@alextis59/athena";
78
+
79
+ export default defineConfig({
80
+ index: {
81
+ include: ["**/*.md", "**/*.mdx", "**/*.pdf", "**/*.html"],
82
+ exclude: ["node_modules/**", "dist/**", ".git/**"]
83
+ },
84
+ embeddings: {
85
+ provider: "transformers-js",
86
+ model: "mixedbread-ai/mxbai-embed-xsmall-v1",
87
+ dimensions: 384,
88
+ pooling: "mean",
89
+ normalize: true,
90
+ allowRemoteDocumentText: false
91
+ },
92
+ chat: {
93
+ provider: "none",
94
+ model: null,
95
+ allowRemoteDocumentText: false
96
+ }
97
+ });
98
+ ```
99
+
100
+ Optional embedding providers are `ollama`, `openai`, `voyage`, `cohere`, and
101
+ `gemini`. Cloud providers require `allowRemoteDocumentText: true` and their API
102
+ key environment variable:
103
+
104
+ - `OPENAI_API_KEY`
105
+ - `VOYAGE_API_KEY`
106
+ - `COHERE_API_KEY`
107
+ - `GEMINI_API_KEY`
108
+
109
+ Ollama uses the local `/api/embed` endpoint and honors `OLLAMA_HOST` when set.
110
+
111
+ ## Citations
112
+
113
+ Answers are required to cite retrieved source material. Athena validates
114
+ Markdown line ranges, PDF page and region metadata, source visibility during the
115
+ turn, and out-of-range citations before accepting an answer.
116
+
117
+ PDF citations include page, region, confidence, and warning metadata when
118
+ available. Low-confidence PDF regions are surfaced as uncertain in the UI.
119
+
120
+ ## MCP Integration
121
+
122
+ `athena mcp` exposes read-only retrieval tools for external coding agents:
123
+
124
+ - `searchDocs`
125
+ - `readSourceRange`
126
+ - `readPdfSource`
127
+ - `grepDocs`
128
+ - `listDocs`
129
+ - `relatedChunks`
130
+
131
+ See [docs/mcp-integration.md](docs/mcp-integration.md) for OpenCode and generic
132
+ MCP setup examples.
133
+
134
+ ## Development
135
+
136
+ ```bash
137
+ npm run format:check
138
+ npm run lint
139
+ npm run typecheck
140
+ npm test
141
+ npm run build
142
+ npm run eval
143
+ ```
144
+
145
+ The offline evaluation validates the committed corpus manifest, ground-truth
146
+ questions, supported document types, hybrid retrieval behavior, PDF handling,
147
+ and answer citation policy.
@@ -0,0 +1,7 @@
1
+ import type { AgentEvent, AgentTurnInput, AgentTurnResult } from "./types.js";
2
+ export interface AskQuestionInput extends AgentTurnInput {
3
+ onEvent?: (event: AgentEvent) => void | Promise<void>;
4
+ }
5
+ export declare function askQuestion(input: AskQuestionInput): Promise<AgentTurnResult>;
6
+ export declare function renderTerminalCitations(answer: string): string;
7
+ //# sourceMappingURL=ask.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ask.d.ts","sourceRoot":"","sources":["../../src/agent/ask.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE9E,MAAM,WAAW,gBAAiB,SAAQ,cAAc;IACtD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvD;AAED,wBAAsB,WAAW,CAC/B,KAAK,EAAE,gBAAgB,GACtB,OAAO,CAAC,eAAe,CAAC,CAsB1B;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAc9D"}
@@ -0,0 +1,35 @@
1
+ import { parseAnswerCitations } from "./citations.js";
2
+ import { runAgentTurn } from "./loop.js";
3
+ export async function askQuestion(input) {
4
+ let result = null;
5
+ for await (const event of runAgentTurn(input)) {
6
+ await input.onEvent?.(event);
7
+ if (event.type === "complete") {
8
+ result = {
9
+ answer: event.answer,
10
+ finishReason: event.finishReason
11
+ };
12
+ }
13
+ }
14
+ if (result === null) {
15
+ return {
16
+ answer: "",
17
+ finishReason: "stop"
18
+ };
19
+ }
20
+ return result;
21
+ }
22
+ export function renderTerminalCitations(answer) {
23
+ const citations = parseAnswerCitations(answer);
24
+ if (citations.length === 0) {
25
+ return "";
26
+ }
27
+ return [
28
+ "",
29
+ "",
30
+ "Citations:",
31
+ ...citations.map((citation) => `- ${citation.label}`),
32
+ ""
33
+ ].join("\n");
34
+ }
35
+ //# sourceMappingURL=ask.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ask.js","sourceRoot":"","sources":["../../src/agent/ask.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAOzC,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,KAAuB;IAEvB,IAAI,MAAM,GAA2B,IAAI,CAAC;IAE1C,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9C,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC;QAE7B,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC9B,MAAM,GAAG;gBACP,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,YAAY,EAAE,KAAK,CAAC,YAAY;aACjC,CAAC;QACJ,CAAC;IACH,CAAC;IAED,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,OAAO;YACL,MAAM,EAAE,EAAE;YACV,YAAY,EAAE,MAAM;SACrB,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,MAAc;IACpD,MAAM,SAAS,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAE/C,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO;QACL,EAAE;QACF,EAAE;QACF,YAAY;QACZ,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,KAAK,QAAQ,CAAC,KAAK,EAAE,CAAC;QACrD,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
@@ -0,0 +1,27 @@
1
+ import type { RetrievalToolRuntime } from "../retrieval/index.js";
2
+ import type { Citation } from "../shared/types.js";
3
+ export interface ParsedTextCitation {
4
+ label: string;
5
+ path: string;
6
+ startLine: number;
7
+ endLine: number;
8
+ }
9
+ export interface ParsedPdfCitation {
10
+ label: string;
11
+ path: string;
12
+ page: number;
13
+ regionId?: string;
14
+ }
15
+ export type ParsedCitation = ParsedTextCitation | ParsedPdfCitation;
16
+ export interface ValidateAnswerCitationsInput {
17
+ root: string;
18
+ answer: string;
19
+ runtime: RetrievalToolRuntime;
20
+ }
21
+ export declare function parseTextCitations(answer: string): ParsedTextCitation[];
22
+ export declare function parsePdfCitations(answer: string): ParsedPdfCitation[];
23
+ export declare function parseAnswerCitations(answer: string): ParsedCitation[];
24
+ export declare function serializeTextCitation(citation: ParsedTextCitation): string;
25
+ export declare function serializePdfCitation(citation: ParsedPdfCitation): string;
26
+ export declare function validateAnswerCitations(input: ValidateAnswerCitationsInput): Promise<Citation[]>;
27
+ //# sourceMappingURL=citations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"citations.d.ts","sourceRoot":"","sources":["../../src/agent/citations.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,KAAK,EACV,QAAQ,EAIT,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,cAAc,GAAG,kBAAkB,GAAG,iBAAiB,CAAC;AAEpE,MAAM,WAAW,4BAA4B;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,oBAAoB,CAAC;CAC/B;AAWD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAEvE;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAErE;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,EAAE,CAOrE;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,MAAM,CAI1E;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,MAAM,CAIxE;AAED,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,4BAA4B,GAClC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAkFrB"}
@@ -0,0 +1,190 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { UserFacingError } from "../errors.js";
4
+ const textCitationPattern = /\[([^\]\n:]+(?:\/[^\]\n:]+)*):(\d+)-(\d+)\]/gu;
5
+ const pdfCitationPattern = /\[([^\]\n]+?\.pdf)\s+p\.(\d+)(?:#([^\]\n\s]+))?\]/giu;
6
+ export function parseTextCitations(answer) {
7
+ return parseTextCitationMatches(answer).map((match) => match.citation);
8
+ }
9
+ export function parsePdfCitations(answer) {
10
+ return parsePdfCitationMatches(answer).map((match) => match.citation);
11
+ }
12
+ export function parseAnswerCitations(answer) {
13
+ return [
14
+ ...parseTextCitationMatches(answer),
15
+ ...parsePdfCitationMatches(answer)
16
+ ]
17
+ .sort((left, right) => left.index - right.index)
18
+ .map((match) => match.citation);
19
+ }
20
+ export function serializeTextCitation(citation) {
21
+ return `[${citation.path}:${String(citation.startLine)}-${String(citation.endLine)}]`;
22
+ }
23
+ export function serializePdfCitation(citation) {
24
+ const region = citation.regionId === undefined ? "" : `#${citation.regionId}`;
25
+ return `[${citation.path} p.${String(citation.page)}${region}]`;
26
+ }
27
+ export async function validateAnswerCitations(input) {
28
+ const parsed = parseAnswerCitations(input.answer);
29
+ if (parsed.length === 0) {
30
+ if (requiresCitation(input.answer)) {
31
+ throw new UserFacingError("Athena answer requires at least one source citation.");
32
+ }
33
+ return [];
34
+ }
35
+ const citations = [];
36
+ for (const parsedCitation of parsed) {
37
+ validateCitationSourcePath(parsedCitation.label, parsedCitation.path);
38
+ const indexedSource = input.runtime.getDoc(parsedCitation.path);
39
+ if (indexedSource === null) {
40
+ throw new UserFacingError(`Citation path is not indexed: ${parsedCitation.path}`);
41
+ }
42
+ if (isParsedPdfCitation(parsedCitation)) {
43
+ validatePdfCitation(parsedCitation);
44
+ if (indexedSource.kind !== "pdf") {
45
+ throw new UserFacingError(`Citation path is not a PDF: ${parsedCitation.path}`);
46
+ }
47
+ const locator = findReadPdfLocator(input.runtime.trace.readLocators, parsedCitation);
48
+ if (locator === null) {
49
+ throw new UserFacingError(`Citation was not retrieved or read during this turn: ${parsedCitation.label}`);
50
+ }
51
+ citations.push({
52
+ label: parsedCitation.label,
53
+ locator
54
+ });
55
+ continue;
56
+ }
57
+ validateTextCitation(parsedCitation);
58
+ if (indexedSource.kind === "pdf") {
59
+ throw new UserFacingError(`PDF citations must use page labels: ${parsedCitation.label}`);
60
+ }
61
+ const locator = {
62
+ type: "text",
63
+ path: parsedCitation.path,
64
+ startLine: parsedCitation.startLine,
65
+ endLine: parsedCitation.endLine
66
+ };
67
+ await validateLineBounds(input.root, locator);
68
+ if (!wasTextReadDuringTurn(input.runtime.trace.readLocators, locator)) {
69
+ throw new UserFacingError(`Citation was not retrieved or read during this turn: ${parsedCitation.label}`);
70
+ }
71
+ citations.push({
72
+ label: parsedCitation.label,
73
+ locator
74
+ });
75
+ }
76
+ return citations;
77
+ }
78
+ function parseTextCitationMatches(answer) {
79
+ const citations = [];
80
+ for (const match of answer.matchAll(textCitationPattern)) {
81
+ const label = match[0];
82
+ const sourcePath = match[1];
83
+ const startLine = Number(match[2]);
84
+ const endLine = Number(match[3]);
85
+ if (sourcePath === undefined ||
86
+ !Number.isInteger(startLine) ||
87
+ !Number.isInteger(endLine)) {
88
+ continue;
89
+ }
90
+ citations.push({
91
+ index: match.index ?? 0,
92
+ citation: {
93
+ label,
94
+ path: sourcePath,
95
+ startLine,
96
+ endLine
97
+ }
98
+ });
99
+ }
100
+ return citations;
101
+ }
102
+ function parsePdfCitationMatches(answer) {
103
+ const citations = [];
104
+ for (const match of answer.matchAll(pdfCitationPattern)) {
105
+ const label = match[0];
106
+ const sourcePath = match[1];
107
+ const page = Number(match[2]);
108
+ const regionId = match[3];
109
+ if (sourcePath === undefined ||
110
+ !Number.isInteger(page) ||
111
+ page < 1 ||
112
+ page > Number.MAX_SAFE_INTEGER) {
113
+ continue;
114
+ }
115
+ const citation = {
116
+ label,
117
+ path: sourcePath.trim(),
118
+ page
119
+ };
120
+ if (regionId !== undefined) {
121
+ citation.regionId = regionId;
122
+ }
123
+ citations.push({
124
+ index: match.index ?? 0,
125
+ citation
126
+ });
127
+ }
128
+ return citations;
129
+ }
130
+ function isParsedPdfCitation(citation) {
131
+ return "page" in citation;
132
+ }
133
+ function validateCitationSourcePath(label, sourcePath) {
134
+ if (sourcePath.trim() === "" ||
135
+ sourcePath.includes("..") ||
136
+ path.isAbsolute(sourcePath)) {
137
+ throw new UserFacingError(`Citation path must be repository-relative: ${label}`);
138
+ }
139
+ }
140
+ function validateTextCitation(citation) {
141
+ if (citation.startLine < 1 || citation.endLine < citation.startLine) {
142
+ throw new UserFacingError(`Citation line range is invalid: ${citation.label}`);
143
+ }
144
+ }
145
+ function validatePdfCitation(citation) {
146
+ if (!Number.isInteger(citation.page) || citation.page < 1) {
147
+ throw new UserFacingError(`PDF citation page is invalid: ${citation.label}`);
148
+ }
149
+ if (citation.regionId !== undefined && citation.regionId.trim() === "") {
150
+ throw new UserFacingError(`PDF citation region is invalid: ${citation.label}`);
151
+ }
152
+ }
153
+ async function validateLineBounds(root, locator) {
154
+ const fileText = await readFile(path.join(root, locator.path), "utf8");
155
+ const lineCount = fileText.replace(/\r\n?/gu, "\n").split("\n").length;
156
+ if (locator.endLine > lineCount) {
157
+ throw new UserFacingError(`Citation line range is outside ${locator.path}: ${String(locator.startLine)}-${String(locator.endLine)}`);
158
+ }
159
+ }
160
+ function wasTextReadDuringTurn(readLocators, locator) {
161
+ return readLocators.some((readLocator) => readLocator.type === "text" &&
162
+ readLocator.path === locator.path &&
163
+ locator.startLine >= readLocator.startLine &&
164
+ locator.endLine <= readLocator.endLine);
165
+ }
166
+ function findReadPdfLocator(readLocators, citation) {
167
+ const candidates = readLocators.filter((readLocator) => readLocator.type === "pdf" &&
168
+ readLocator.path === citation.path &&
169
+ readLocator.page === citation.page);
170
+ if (citation.regionId === undefined) {
171
+ return candidates[0] ?? null;
172
+ }
173
+ return (candidates.find((locator) => locator.regionId === citation.regionId) ?? null);
174
+ }
175
+ function requiresCitation(answer) {
176
+ const normalized = answer.trim().toLowerCase();
177
+ if (normalized === "") {
178
+ return false;
179
+ }
180
+ return ![
181
+ "could not",
182
+ "cannot",
183
+ "unable",
184
+ "not enough evidence",
185
+ "not verified",
186
+ "no indexed source",
187
+ "tool budget"
188
+ ].some((marker) => normalized.includes(marker));
189
+ }
190
+ //# sourceMappingURL=citations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"citations.js","sourceRoot":"","sources":["../../src/agent/citations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { ModelEvent, ModelProvider, ModelProviderRequest } from "./types.js";
2
+ export declare class FakeModelProvider implements ModelProvider {
3
+ readonly requests: ModelProviderRequest[];
4
+ private readonly responses;
5
+ constructor(responses?: Iterable<readonly ModelEvent[]>);
6
+ enqueue(response: readonly ModelEvent[]): void;
7
+ streamResponse(input: ModelProviderRequest): AsyncIterable<ModelEvent>;
8
+ }
9
+ //# sourceMappingURL=fake-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fake-provider.d.ts","sourceRoot":"","sources":["../../src/agent/fake-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,UAAU,EAEV,aAAa,EACb,oBAAoB,EAErB,MAAM,YAAY,CAAC;AAEpB,qBAAa,iBAAkB,YAAW,aAAa;IACrD,SAAgB,QAAQ,EAAE,oBAAoB,EAAE,CAAM;IAEtD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiB;gBAExB,SAAS,GAAE,QAAQ,CAAC,SAAS,UAAU,EAAE,CAAM;IAI3D,OAAO,CAAC,QAAQ,EAAE,SAAS,UAAU,EAAE,GAAG,IAAI;IAIvC,cAAc,CAC1B,KAAK,EAAE,oBAAoB,GAC1B,aAAa,CAAC,UAAU,CAAC;CAU7B"}
@@ -0,0 +1,51 @@
1
+ export class FakeModelProvider {
2
+ requests = [];
3
+ responses;
4
+ constructor(responses = []) {
5
+ this.responses = [...responses].map((response) => [...response]);
6
+ }
7
+ enqueue(response) {
8
+ this.responses.push([...response]);
9
+ }
10
+ async *streamResponse(input) {
11
+ this.requests.push(cloneRequest(input));
12
+ await Promise.resolve();
13
+ for (const event of this.responses.shift() ?? [
14
+ { type: "complete", finishReason: "stop" }
15
+ ]) {
16
+ yield event;
17
+ }
18
+ }
19
+ }
20
+ function cloneRequest(input) {
21
+ const request = {
22
+ model: input.model,
23
+ messages: input.messages.map(cloneMessage),
24
+ tools: input.tools.map(cloneTool)
25
+ };
26
+ if (input.temperature !== undefined) {
27
+ request.temperature = input.temperature;
28
+ }
29
+ return request;
30
+ }
31
+ function cloneMessage(message) {
32
+ if (message.role !== "assistant") {
33
+ return { ...message };
34
+ }
35
+ const clone = {
36
+ role: "assistant",
37
+ content: message.content
38
+ };
39
+ if (message.toolCalls !== undefined) {
40
+ clone.toolCalls = message.toolCalls.map((toolCall) => ({ ...toolCall }));
41
+ }
42
+ return clone;
43
+ }
44
+ function cloneTool(tool) {
45
+ return {
46
+ name: tool.name,
47
+ description: tool.description,
48
+ inputSchema: { ...tool.inputSchema }
49
+ };
50
+ }
51
+ //# sourceMappingURL=fake-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fake-provider.js","sourceRoot":"","sources":["../../src/agent/fake-provider.ts"],"names":[],"mappings":"AASA,MAAM,OAAO,iBAAiB;IACZ,QAAQ,GAA2B,EAAE,CAAC;IAErC,SAAS,CAAiB;IAE3C,YAAmB,YAA6C,EAAE;QAChE,IAAI,CAAC,SAAS,GAAG,CAAC,GAAG,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;IACnE,CAAC;IAEM,OAAO,CAAC,QAA+B;QAC5C,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;IACrC,CAAC;IAEM,KAAK,CAAC,CAAC,cAAc,CAC1B,KAA2B;QAE3B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;QACxC,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;QAExB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI;YAC5C,EAAE,IAAI,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,EAAE;SAC3C,EAAE,CAAC;YACF,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;CACF;AAED,SAAS,YAAY,CAAC,KAA2B;IAC/C,MAAM,OAAO,GAAyB;QACpC,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,YAAY,CAAC;QAC1C,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC;KAClC,CAAC;IAEF,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;QACpC,OAAO,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;IAC1C,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,YAAY,CAAC,OAAqB;IACzC,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;QACjC,OAAO,EAAE,GAAG,OAAO,EAAE,CAAC;IACxB,CAAC;IAED,MAAM,KAAK,GAA0B;QACnC,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,OAAO,CAAC,OAAO;KACzB,CAAC;IAEF,IAAI,OAAO,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QACpC,KAAK,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,QAAQ,EAAE,CAAC,CAAC,CAAC;IAC3E,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,SAAS,CAAC,IAAyB;IAC1C,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,WAAW,EAAE,EAAE,GAAG,IAAI,CAAC,WAAW,EAAE;KACrC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,10 @@
1
+ export { FakeModelProvider } from "./fake-provider.js";
2
+ export { askQuestion, renderTerminalCitations } from "./ask.js";
3
+ export type { AskQuestionInput } from "./ask.js";
4
+ export { parseAnswerCitations, parsePdfCitations, parseTextCitations, serializePdfCitation, serializeTextCitation, validateAnswerCitations } from "./citations.js";
5
+ export type { ParsedCitation, ParsedPdfCitation, ParsedTextCitation, ValidateAnswerCitationsInput } from "./citations.js";
6
+ export { DEFAULT_MAX_AGENT_STEPS, buildModelMessages, createModelToolDefinitions, runAgentTurn } from "./loop.js";
7
+ export { OllamaModelProvider, createConfiguredModelProvider, validateModelProviderConfig } from "./providers.js";
8
+ export type { CreateModelProviderOptions, FetchLike } from "./providers.js";
9
+ export type { AssistantModelMessage, AgentEvent, AgentTurnInput, AgentTurnResult, CompactConversationTurn, ModelEvent, ModelFinishReason, ModelMessage, ModelProvider, ModelProviderRequest, ModelRole, ModelToolCall, ModelToolCallEvent, ModelToolDefinition, ModelToolResultMessage, TextModelMessage } from "./types.js";
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agent/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAChE,YAAY,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACjD,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EACxB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,kBAAkB,EAClB,4BAA4B,EAC7B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,uBAAuB,EACvB,kBAAkB,EAClB,0BAA0B,EAC1B,YAAY,EACb,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,mBAAmB,EACnB,6BAA6B,EAC7B,2BAA2B,EAC5B,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,0BAA0B,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC5E,YAAY,EACV,qBAAqB,EACrB,UAAU,EACV,cAAc,EACd,eAAe,EACf,uBAAuB,EACvB,UAAU,EACV,iBAAiB,EACjB,YAAY,EACZ,aAAa,EACb,oBAAoB,EACpB,SAAS,EACT,aAAa,EACb,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,EACtB,gBAAgB,EACjB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { FakeModelProvider } from "./fake-provider.js";
2
+ export { askQuestion, renderTerminalCitations } from "./ask.js";
3
+ export { parseAnswerCitations, parsePdfCitations, parseTextCitations, serializePdfCitation, serializeTextCitation, validateAnswerCitations } from "./citations.js";
4
+ export { DEFAULT_MAX_AGENT_STEPS, buildModelMessages, createModelToolDefinitions, runAgentTurn } from "./loop.js";
5
+ export { OllamaModelProvider, createConfiguredModelProvider, validateModelProviderConfig } from "./providers.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/agent/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAEhE,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EACxB,MAAM,gBAAgB,CAAC;AAOxB,OAAO,EACL,uBAAuB,EACvB,kBAAkB,EAClB,0BAA0B,EAC1B,YAAY,EACb,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,mBAAmB,EACnB,6BAA6B,EAC7B,2BAA2B,EAC5B,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { createModelToolDefinitions } from "./tools.js";
2
+ import type { AgentEvent, AgentTurnInput, CompactConversationTurn, ModelMessage } from "./types.js";
3
+ export declare const DEFAULT_MAX_AGENT_STEPS = 6;
4
+ export declare function runAgentTurn(input: AgentTurnInput): AsyncIterable<AgentEvent>;
5
+ export declare function buildModelMessages(input: {
6
+ question: string;
7
+ previousTurns?: CompactConversationTurn[];
8
+ pinnedSources?: string[];
9
+ }): ModelMessage[];
10
+ export { createModelToolDefinitions };
11
+ //# sourceMappingURL=loop.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../../src/agent/loop.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,0BAA0B,EAAoB,MAAM,YAAY,CAAC;AAE1E,OAAO,KAAK,EACV,UAAU,EACV,cAAc,EACd,uBAAuB,EAEvB,YAAY,EAEb,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,uBAAuB,IAAI,CAAC;AAEzC,wBAAuB,YAAY,CACjC,KAAK,EAAE,cAAc,GACpB,aAAa,CAAC,UAAU,CAAC,CAyF3B;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,uBAAuB,EAAE,CAAC;IAC1C,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B,GAAG,YAAY,EAAE,CA4BjB;AAED,OAAO,EAAE,0BAA0B,EAAE,CAAC"}