@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.
- package/LICENSE +15 -0
- package/README.md +147 -0
- package/dist/agent/ask.d.ts +7 -0
- package/dist/agent/ask.d.ts.map +1 -0
- package/dist/agent/ask.js +35 -0
- package/dist/agent/ask.js.map +1 -0
- package/dist/agent/citations.d.ts +27 -0
- package/dist/agent/citations.d.ts.map +1 -0
- package/dist/agent/citations.js +190 -0
- package/dist/agent/citations.js.map +1 -0
- package/dist/agent/fake-provider.d.ts +9 -0
- package/dist/agent/fake-provider.d.ts.map +1 -0
- package/dist/agent/fake-provider.js +51 -0
- package/dist/agent/fake-provider.js.map +1 -0
- package/dist/agent/index.d.ts +10 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +6 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/loop.d.ts +11 -0
- package/dist/agent/loop.d.ts.map +1 -0
- package/dist/agent/loop.js +156 -0
- package/dist/agent/loop.js.map +1 -0
- package/dist/agent/providers.d.ts +17 -0
- package/dist/agent/providers.d.ts.map +1 -0
- package/dist/agent/providers.js +171 -0
- package/dist/agent/providers.js.map +1 -0
- package/dist/agent/tools.d.ts +8 -0
- package/dist/agent/tools.d.ts.map +1 -0
- package/dist/agent/tools.js +233 -0
- package/dist/agent/tools.js.map +1 -0
- package/dist/agent/types.d.ts +84 -0
- package/dist/agent/types.d.ts.map +1 -0
- package/dist/agent/types.js +2 -0
- package/dist/agent/types.js.map +1 -0
- package/dist/cli/help.d.ts +2 -0
- package/dist/cli/help.d.ts.map +1 -0
- package/dist/cli/help.js +28 -0
- package/dist/cli/help.js.map +1 -0
- package/dist/cli/main.d.ts +3 -0
- package/dist/cli/main.d.ts.map +1 -0
- package/dist/cli/main.js +5 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/options.d.ts +21 -0
- package/dist/cli/options.d.ts.map +1 -0
- package/dist/cli/options.js +97 -0
- package/dist/cli/options.js.map +1 -0
- package/dist/cli/run.d.ts +21 -0
- package/dist/cli/run.d.ts.map +1 -0
- package/dist/cli/run.js +144 -0
- package/dist/cli/run.js.map +1 -0
- package/dist/config/index.d.ts +4 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +3 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/loader.d.ts +14 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +352 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +6 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +72 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/config/types.d.ts +53 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +2 -0
- package/dist/config/types.js.map +1 -0
- package/dist/doctor/doctor.d.ts +47 -0
- package/dist/doctor/doctor.d.ts.map +1 -0
- package/dist/doctor/doctor.js +159 -0
- package/dist/doctor/doctor.js.map +1 -0
- package/dist/embeddings/index.d.ts +117 -0
- package/dist/embeddings/index.d.ts.map +1 -0
- package/dist/embeddings/index.js +515 -0
- package/dist/embeddings/index.js.map +1 -0
- package/dist/errors.d.ts +19 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +37 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/indexer/discovery.d.ts +10 -0
- package/dist/indexer/discovery.d.ts.map +1 -0
- package/dist/indexer/discovery.js +38 -0
- package/dist/indexer/discovery.js.map +1 -0
- package/dist/indexer/hash.d.ts +3 -0
- package/dist/indexer/hash.d.ts.map +1 -0
- package/dist/indexer/hash.js +11 -0
- package/dist/indexer/hash.js.map +1 -0
- package/dist/indexer/index.d.ts +7 -0
- package/dist/indexer/index.d.ts.map +1 -0
- package/dist/indexer/index.js +5 -0
- package/dist/indexer/index.js.map +1 -0
- package/dist/indexer/kinds.d.ts +4 -0
- package/dist/indexer/kinds.d.ts.map +1 -0
- package/dist/indexer/kinds.js +38 -0
- package/dist/indexer/kinds.js.map +1 -0
- package/dist/indexer/run.d.ts +42 -0
- package/dist/indexer/run.d.ts.map +1 -0
- package/dist/indexer/run.js +563 -0
- package/dist/indexer/run.js.map +1 -0
- package/dist/logging/logger.d.ts +11 -0
- package/dist/logging/logger.d.ts.map +1 -0
- package/dist/logging/logger.js +18 -0
- package/dist/logging/logger.js.map +1 -0
- package/dist/mcp/index.d.ts +35 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +392 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/parsers/chunking.d.ts +4 -0
- package/dist/parsers/chunking.d.ts.map +1 -0
- package/dist/parsers/chunking.js +112 -0
- package/dist/parsers/chunking.js.map +1 -0
- package/dist/parsers/index.d.ts +8 -0
- package/dist/parsers/index.d.ts.map +1 -0
- package/dist/parsers/index.js +5 -0
- package/dist/parsers/index.js.map +1 -0
- package/dist/parsers/line-parser.d.ts +13 -0
- package/dist/parsers/line-parser.d.ts.map +1 -0
- package/dist/parsers/line-parser.js +242 -0
- package/dist/parsers/line-parser.js.map +1 -0
- package/dist/parsers/normalize.d.ts +4 -0
- package/dist/parsers/normalize.d.ts.map +1 -0
- package/dist/parsers/normalize.js +17 -0
- package/dist/parsers/normalize.js.map +1 -0
- package/dist/parsers/parser.d.ts +14 -0
- package/dist/parsers/parser.d.ts.map +1 -0
- package/dist/parsers/parser.js +77 -0
- package/dist/parsers/parser.js.map +1 -0
- package/dist/parsers/pdf2llm.d.ts +14 -0
- package/dist/parsers/pdf2llm.d.ts.map +1 -0
- package/dist/parsers/pdf2llm.js +215 -0
- package/dist/parsers/pdf2llm.js.map +1 -0
- package/dist/parsers/types.d.ts +48 -0
- package/dist/parsers/types.d.ts.map +1 -0
- package/dist/parsers/types.js +2 -0
- package/dist/parsers/types.js.map +1 -0
- package/dist/retrieval/index.d.ts +4 -0
- package/dist/retrieval/index.d.ts.map +1 -0
- package/dist/retrieval/index.js +3 -0
- package/dist/retrieval/index.js.map +1 -0
- package/dist/retrieval/schemas.d.ts +127 -0
- package/dist/retrieval/schemas.d.ts.map +1 -0
- package/dist/retrieval/schemas.js +65 -0
- package/dist/retrieval/schemas.js.map +1 -0
- package/dist/retrieval/tools.d.ts +31 -0
- package/dist/retrieval/tools.d.ts.map +1 -0
- package/dist/retrieval/tools.js +803 -0
- package/dist/retrieval/tools.js.map +1 -0
- package/dist/retrieval/types.d.ts +104 -0
- package/dist/retrieval/types.d.ts.map +1 -0
- package/dist/retrieval/types.js +2 -0
- package/dist/retrieval/types.js.map +1 -0
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +2 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/server.d.ts +49 -0
- package/dist/server/server.d.ts.map +1 -0
- package/dist/server/server.js +517 -0
- package/dist/server/server.js.map +1 -0
- package/dist/shared/types.d.ts +98 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/types.js +2 -0
- package/dist/shared/types.js.map +1 -0
- package/dist/storage/database.d.ts +18 -0
- package/dist/storage/database.d.ts.map +1 -0
- package/dist/storage/database.js +66 -0
- package/dist/storage/database.js.map +1 -0
- package/dist/storage/index.d.ts +8 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +5 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/migrations.d.ts +15 -0
- package/dist/storage/migrations.d.ts.map +1 -0
- package/dist/storage/migrations.js +170 -0
- package/dist/storage/migrations.js.map +1 -0
- package/dist/storage/paths.d.ts +15 -0
- package/dist/storage/paths.d.ts.map +1 -0
- package/dist/storage/paths.js +27 -0
- package/dist/storage/paths.js.map +1 -0
- package/dist/storage/schema.d.ts +11 -0
- package/dist/storage/schema.d.ts.map +1 -0
- package/dist/storage/schema.js +40 -0
- package/dist/storage/schema.js.map +1 -0
- package/dist/ui/index.d.ts +2 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +2 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/static-app.d.ts +2 -0
- package/dist/ui/static-app.d.ts.map +1 -0
- package/dist/ui/static-app.js +735 -0
- package/dist/ui/static-app.js.map +1 -0
- package/docs/adr/0001-sqlite-driver.md +23 -0
- package/docs/agentic-rag-specifications.md +659 -0
- package/docs/agentic-rag-study.md +1056 -0
- package/docs/implementation-plan.md +1425 -0
- package/docs/mcp-integration.md +154 -0
- package/docs/validation-corpus.md +71 -0
- 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"}
|