pi-para 0.6.0 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +0 -9
- package/CHANGELOG.md +22 -0
- package/CONFIGURATION.md +5 -23
- package/README.md +7 -31
- package/SETUP.md +5 -3
- package/STRUCTURE.md +0 -9
- package/dist/atomic-write.d.ts +2 -0
- package/dist/atomic-write.d.ts.map +1 -0
- package/dist/atomic-write.js +18 -0
- package/dist/atomic-write.js.map +1 -0
- package/dist/capture.d.ts +34 -0
- package/dist/capture.d.ts.map +1 -0
- package/dist/capture.js +461 -0
- package/dist/capture.js.map +1 -0
- package/dist/cli-legacy.d.ts +4 -0
- package/dist/cli-legacy.d.ts.map +1 -0
- package/dist/cli-legacy.js +41 -0
- package/dist/cli-legacy.js.map +1 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +427 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands.d.ts +15 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +791 -0
- package/dist/commands.js.map +1 -0
- package/dist/config.d.ts +94 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +228 -0
- package/dist/config.js.map +1 -0
- package/dist/context.d.ts +63 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +311 -0
- package/dist/context.js.map +1 -0
- package/dist/credentials.d.ts +27 -0
- package/dist/credentials.d.ts.map +1 -0
- package/dist/credentials.js +85 -0
- package/dist/credentials.js.map +1 -0
- package/dist/daemon.d.ts +49 -0
- package/dist/daemon.d.ts.map +1 -0
- package/dist/daemon.js +226 -0
- package/dist/daemon.js.map +1 -0
- package/dist/doctor.d.ts +20 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +197 -0
- package/dist/doctor.js.map +1 -0
- package/dist/frontmatter.d.ts +59 -0
- package/dist/frontmatter.d.ts.map +1 -0
- package/dist/frontmatter.js +170 -0
- package/dist/frontmatter.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +357 -0
- package/dist/index.js.map +1 -0
- package/dist/ingest.d.ts +88 -0
- package/dist/ingest.d.ts.map +1 -0
- package/dist/ingest.js +105 -0
- package/dist/ingest.js.map +1 -0
- package/dist/link-discovery.d.ts +40 -0
- package/dist/link-discovery.d.ts.map +1 -0
- package/dist/link-discovery.js +122 -0
- package/dist/link-discovery.js.map +1 -0
- package/dist/link-utils.d.ts +30 -0
- package/dist/link-utils.d.ts.map +1 -0
- package/dist/link-utils.js +145 -0
- package/dist/link-utils.js.map +1 -0
- package/dist/lint.d.ts +39 -0
- package/dist/lint.d.ts.map +1 -0
- package/dist/lint.js +827 -0
- package/dist/lint.js.map +1 -0
- package/dist/maintainer.d.ts +24 -0
- package/dist/maintainer.d.ts.map +1 -0
- package/dist/maintainer.js +358 -0
- package/dist/maintainer.js.map +1 -0
- package/dist/model-resolver.d.ts +30 -0
- package/dist/model-resolver.d.ts.map +1 -0
- package/dist/model-resolver.js +71 -0
- package/dist/model-resolver.js.map +1 -0
- package/dist/paths.d.ts +20 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +33 -0
- package/dist/paths.js.map +1 -0
- package/dist/processor.d.ts +14 -0
- package/dist/processor.d.ts.map +1 -0
- package/dist/processor.js +361 -0
- package/dist/processor.js.map +1 -0
- package/dist/qmd-providers.d.ts +12 -0
- package/dist/qmd-providers.d.ts.map +1 -0
- package/dist/qmd-providers.js +45 -0
- package/dist/qmd-providers.js.map +1 -0
- package/dist/query.d.ts +69 -0
- package/dist/query.d.ts.map +1 -0
- package/dist/query.js +120 -0
- package/dist/query.js.map +1 -0
- package/dist/raw.d.ts +57 -0
- package/dist/raw.d.ts.map +1 -0
- package/dist/raw.js +219 -0
- package/dist/raw.js.map +1 -0
- package/dist/redact.d.ts +21 -0
- package/dist/redact.d.ts.map +1 -0
- package/dist/redact.js +143 -0
- package/dist/redact.js.map +1 -0
- package/dist/repair.d.ts +11 -0
- package/dist/repair.d.ts.map +1 -0
- package/dist/repair.js +41 -0
- package/dist/repair.js.map +1 -0
- package/dist/scheduler/controls.d.ts +35 -0
- package/dist/scheduler/controls.d.ts.map +1 -0
- package/dist/scheduler/controls.js +98 -0
- package/dist/scheduler/controls.js.map +1 -0
- package/dist/scheduler/index.d.ts +70 -0
- package/dist/scheduler/index.d.ts.map +1 -0
- package/dist/scheduler/index.js +245 -0
- package/dist/scheduler/index.js.map +1 -0
- package/dist/scheduler/leases.d.ts +22 -0
- package/dist/scheduler/leases.d.ts.map +1 -0
- package/dist/scheduler/leases.js +74 -0
- package/dist/scheduler/leases.js.map +1 -0
- package/dist/scheduler/session-capture.d.ts +33 -0
- package/dist/scheduler/session-capture.d.ts.map +1 -0
- package/dist/scheduler/session-capture.js +108 -0
- package/dist/scheduler/session-capture.js.map +1 -0
- package/dist/scheduler/state.d.ts +56 -0
- package/dist/scheduler/state.d.ts.map +1 -0
- package/dist/scheduler/state.js +210 -0
- package/dist/scheduler/state.js.map +1 -0
- package/dist/scope.d.ts +54 -0
- package/dist/scope.d.ts.map +1 -0
- package/dist/scope.js +161 -0
- package/dist/scope.js.map +1 -0
- package/dist/scripts/bulk-link-fix.d.ts +9 -0
- package/dist/scripts/bulk-link-fix.d.ts.map +1 -0
- package/dist/scripts/bulk-link-fix.js +106 -0
- package/dist/scripts/bulk-link-fix.js.map +1 -0
- package/dist/session-tools.d.ts +33 -0
- package/dist/session-tools.d.ts.map +1 -0
- package/dist/session-tools.js +211 -0
- package/dist/session-tools.js.map +1 -0
- package/dist/settings.d.ts +37 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +176 -0
- package/dist/settings.js.map +1 -0
- package/dist/setup.d.ts +29 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +90 -0
- package/dist/setup.js.map +1 -0
- package/dist/state.d.ts +54 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +176 -0
- package/dist/state.js.map +1 -0
- package/dist/status.d.ts +22 -0
- package/dist/status.d.ts.map +1 -0
- package/dist/status.js +93 -0
- package/dist/status.js.map +1 -0
- package/dist/store.d.ts +71 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +282 -0
- package/dist/store.js.map +1 -0
- package/dist/summarize.d.ts +60 -0
- package/dist/summarize.d.ts.map +1 -0
- package/dist/summarize.js +266 -0
- package/dist/summarize.js.map +1 -0
- package/dist/tag-registry.d.ts +56 -0
- package/dist/tag-registry.d.ts.map +1 -0
- package/dist/tag-registry.js +146 -0
- package/dist/tag-registry.js.map +1 -0
- package/dist/templates/prompts.d.ts +51 -0
- package/dist/templates/prompts.d.ts.map +1 -0
- package/dist/templates/prompts.js +203 -0
- package/dist/templates/prompts.js.map +1 -0
- package/dist/tools.d.ts +26 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +1198 -0
- package/dist/tools.js.map +1 -0
- package/dist/watcher.d.ts +25 -0
- package/dist/watcher.d.ts.map +1 -0
- package/dist/watcher.js +84 -0
- package/dist/watcher.js.map +1 -0
- package/dist/webui/client/dist/index.html +1885 -0
- package/dist/webui/server.d.ts +31 -0
- package/dist/webui/server.d.ts.map +1 -0
- package/dist/webui/server.js +566 -0
- package/dist/webui/server.js.map +1 -0
- package/dist/wiki-tool-guidance.d.ts +6 -0
- package/dist/wiki-tool-guidance.d.ts.map +1 -0
- package/dist/wiki-tool-guidance.js +70 -0
- package/dist/wiki-tool-guidance.js.map +1 -0
- package/dist/wiki.d.ts +108 -0
- package/dist/wiki.d.ts.map +1 -0
- package/dist/wiki.js +497 -0
- package/dist/wiki.js.map +1 -0
- package/package.json +2 -1
- package/scripts/build-assets.mjs +1 -13
- package/skills/setup/SKILL.md +1 -1
- package/src/cli.ts +0 -70
- package/src/commands.ts +78 -3
- package/src/config.ts +0 -25
- package/src/doctor.ts +21 -1
- package/src/index.ts +16 -38
- package/src/scheduler/index.ts +64 -0
- package/src/settings.ts +88 -0
- package/src/setup.ts +1 -1
- package/src/templates/prompts.ts +0 -56
- package/scripts/gepa/dataset.py +0 -192
- package/scripts/gepa/lm_providers.py +0 -472
- package/scripts/gepa/metric.py +0 -279
- package/scripts/gepa/optimize.py +0 -367
- package/scripts/gepa/program.py +0 -99
- package/scripts/gepa/pyproject.toml +0 -19
- package/scripts/gepa/run-all.sh +0 -53
- package/scripts/gepa/wiki_reader.py +0 -113
- package/src/gepa/index.ts +0 -287
- package/src/gepa/optimized/capture-prompt.txt +0 -65
package/src/templates/prompts.ts
CHANGED
|
@@ -1,63 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* LLM prompt templates for ingest, query, lint, capture, and summarize operations.
|
|
3
|
-
*
|
|
4
|
-
* Use getPrompt(name) to load the GEPA-optimized version (if deployed) or the original.
|
|
5
3
|
*/
|
|
6
4
|
|
|
7
|
-
import { readFileSync, existsSync } from "node:fs";
|
|
8
|
-
import { join, dirname } from "node:path";
|
|
9
|
-
import { homedir } from "node:os";
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Load a prompt by name — returns the GEPA-optimized version if
|
|
13
|
-
* config.gepa.useOptimized is true, otherwise returns the original.
|
|
14
|
-
*
|
|
15
|
-
* Resolution order:
|
|
16
|
-
* 1. User-generated optimized prompt at ~/.pi/wiki/gepa/optimized/{name}.txt
|
|
17
|
-
* 2. Bundled optimized prompt shipped with the package (src/gepa/optimized/{name}.txt)
|
|
18
|
-
* 3. Original constant from this file
|
|
19
|
-
*/
|
|
20
|
-
export function getPrompt(name: string): string {
|
|
21
|
-
const original = _originals()[name];
|
|
22
|
-
if (!original) return "";
|
|
23
|
-
try {
|
|
24
|
-
const cfgPath = join(homedir(), ".pi", "wiki", "config.json");
|
|
25
|
-
if (!existsSync(cfgPath)) return original;
|
|
26
|
-
const cfg = JSON.parse(readFileSync(cfgPath, "utf-8"));
|
|
27
|
-
if (!cfg.gepa?.useOptimized) return original;
|
|
28
|
-
|
|
29
|
-
// 1. Check user-generated optimized prompt
|
|
30
|
-
const userPath = join(homedir(), ".pi", "wiki", "gepa", "optimized", `${name}.txt`);
|
|
31
|
-
if (existsSync(userPath)) {
|
|
32
|
-
const content = readFileSync(userPath, "utf-8").trim();
|
|
33
|
-
if (content.length > 50) return content;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// 2. Check bundled optimized prompt (shipped with package)
|
|
37
|
-
const bundledPath = join(dirname(new URL(import.meta.url).pathname), "..", "gepa", "optimized", `${name}.txt`);
|
|
38
|
-
if (existsSync(bundledPath)) {
|
|
39
|
-
const content = readFileSync(bundledPath, "utf-8").trim();
|
|
40
|
-
if (content.length > 50) return content;
|
|
41
|
-
}
|
|
42
|
-
} catch { /* fall through to original */ }
|
|
43
|
-
return original;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function _originals(): Record<string, string> {
|
|
47
|
-
return {
|
|
48
|
-
"wiki-system-prompt": WIKI_SYSTEM_PROMPT,
|
|
49
|
-
"ingest-prompt": INGEST_PROMPT,
|
|
50
|
-
"query-prompt": QUERY_PROMPT,
|
|
51
|
-
"capture-system-prompt": CAPTURE_SYSTEM_PROMPT,
|
|
52
|
-
"capture-prompt": CAPTURE_PROMPT,
|
|
53
|
-
"explicit-capture-prompt": EXPLICIT_CAPTURE_PROMPT,
|
|
54
|
-
"summarize-system-prompt": SUMMARIZE_SYSTEM_PROMPT,
|
|
55
|
-
"iterative-update-prompt": ITERATIVE_UPDATE_PROMPT,
|
|
56
|
-
"overview-prompt": OVERVIEW_PROMPT,
|
|
57
|
-
"lint-prompt": LINT_PROMPT,
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
|
|
61
5
|
// -- Wiki System Prompt (standalone agent) ------------------------------------
|
|
62
6
|
|
|
63
7
|
/**
|
package/scripts/gepa/dataset.py
DELETED
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
"""Build trainset/valset from real wiki pages.
|
|
2
|
-
|
|
3
|
-
Each example pairs a synthetic task context (derived from the page topic)
|
|
4
|
-
with the actual page body as expected output. The proxy module runs the
|
|
5
|
-
instruction on the task context; the metric scores how well the output
|
|
6
|
-
matches the gold page.
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
from __future__ import annotations
|
|
10
|
-
|
|
11
|
-
import random
|
|
12
|
-
from typing import Any
|
|
13
|
-
|
|
14
|
-
import dspy
|
|
15
|
-
|
|
16
|
-
from wiki_reader import WikiPage, load_all_pages, get_wiki_stats
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
# -- Task context generators --------------------------------------------------
|
|
20
|
-
|
|
21
|
-
def _capture_context(page: WikiPage) -> str:
|
|
22
|
-
"""Generate a synthetic capture-style task context from a wiki page."""
|
|
23
|
-
scope_str = ", ".join(page.scope) if page.scope else "unknown"
|
|
24
|
-
tags_str = ", ".join(page.tags[:5]) if page.tags else ""
|
|
25
|
-
# Simulate what a session about this topic would look like
|
|
26
|
-
return (
|
|
27
|
-
f"A coding session about '{page.title}' in the {scope_str} project. "
|
|
28
|
-
f"Topics covered: {tags_str}. "
|
|
29
|
-
f"Extract and organize the key knowledge from this session into a wiki page."
|
|
30
|
-
)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
def _ingest_context(page: WikiPage) -> str:
|
|
34
|
-
"""Generate a synthetic ingest-style task context."""
|
|
35
|
-
return (
|
|
36
|
-
f"Ingest the following source material about '{page.title}' "
|
|
37
|
-
f"into the PARA wiki. Organize into a structured page with "
|
|
38
|
-
f"proper frontmatter, sections, and cross-references."
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
def _query_context(page: WikiPage) -> str:
|
|
43
|
-
"""Generate a synthetic query-style task context."""
|
|
44
|
-
return (
|
|
45
|
-
f"The user asked about '{page.title}'. "
|
|
46
|
-
f"Search results returned pages related to: {', '.join(page.scope)}. "
|
|
47
|
-
f"Synthesize a helpful answer citing specific wiki pages."
|
|
48
|
-
)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
def _maintenance_context(page: WikiPage) -> str:
|
|
52
|
-
"""Generate a synthetic maintenance-style task context."""
|
|
53
|
-
link_count = len(page.links)
|
|
54
|
-
return (
|
|
55
|
-
f"Review the wiki page '{page.title}' ({page.category}/{page.slug}). "
|
|
56
|
-
f"It has {link_count} outgoing links, scope [{', '.join(page.scope)}], "
|
|
57
|
-
f"tags [{', '.join(page.tags[:5])}]. "
|
|
58
|
-
f"Check for correct categorization, missing links, and content quality."
|
|
59
|
-
)
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
def _tool_context(page: WikiPage) -> str:
|
|
63
|
-
"""Generate a task context for tool instruction optimization."""
|
|
64
|
-
return (
|
|
65
|
-
f"A user wants to work with the wiki page '{page.title}' "
|
|
66
|
-
f"in category '{page.category}', scope [{', '.join(page.scope)}]. "
|
|
67
|
-
f"Guide them on how to use wiki tools effectively."
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
def _skill_context(page: WikiPage) -> str:
|
|
72
|
-
"""Generate a task context for skill optimization."""
|
|
73
|
-
return (
|
|
74
|
-
f"Working on a task related to '{page.title}' in the {', '.join(page.scope)} project. "
|
|
75
|
-
f"Apply the PARA knowledge management methodology to this work."
|
|
76
|
-
)
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
# Target type → context generator
|
|
80
|
-
CONTEXT_GENERATORS = {
|
|
81
|
-
"capture": _capture_context,
|
|
82
|
-
"ingest": _ingest_context,
|
|
83
|
-
"query": _query_context,
|
|
84
|
-
"maintenance": _maintenance_context,
|
|
85
|
-
"tool": _tool_context,
|
|
86
|
-
"skill": _skill_context,
|
|
87
|
-
"system": _capture_context, # system prompts use capture-style context
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
# -- Dataset builder -----------------------------------------------------------
|
|
92
|
-
|
|
93
|
-
def build_dataset(
|
|
94
|
-
wiki_dir: str,
|
|
95
|
-
target_type: str = "capture",
|
|
96
|
-
max_examples: int = 50,
|
|
97
|
-
val_ratio: float = 0.4,
|
|
98
|
-
seed: int = 42,
|
|
99
|
-
) -> tuple[list[dspy.Example], list[dspy.Example]]:
|
|
100
|
-
"""Build train/val datasets from real wiki pages.
|
|
101
|
-
|
|
102
|
-
Args:
|
|
103
|
-
wiki_dir: Path to wiki directory (e.g. ~/.pi/wiki)
|
|
104
|
-
target_type: Type of target being optimized (capture, ingest, query, etc.)
|
|
105
|
-
max_examples: Maximum total examples
|
|
106
|
-
val_ratio: Fraction of examples for validation
|
|
107
|
-
seed: Random seed for reproducible splits
|
|
108
|
-
|
|
109
|
-
Returns:
|
|
110
|
-
(trainset, valset) — lists of dspy.Example
|
|
111
|
-
"""
|
|
112
|
-
pages = load_all_pages(wiki_dir)
|
|
113
|
-
|
|
114
|
-
if not pages:
|
|
115
|
-
raise ValueError(f"No wiki pages found in {wiki_dir}")
|
|
116
|
-
|
|
117
|
-
# Filter to pages with substantial content (at least 200 chars body)
|
|
118
|
-
good_pages = [p for p in pages if len(p.body) >= 200]
|
|
119
|
-
|
|
120
|
-
if len(good_pages) < 4:
|
|
121
|
-
raise ValueError(f"Need at least 4 pages with content, found {len(good_pages)}")
|
|
122
|
-
|
|
123
|
-
# Shuffle deterministically
|
|
124
|
-
rng = random.Random(seed)
|
|
125
|
-
rng.shuffle(good_pages)
|
|
126
|
-
|
|
127
|
-
# Limit to max_examples
|
|
128
|
-
good_pages = good_pages[:max_examples]
|
|
129
|
-
|
|
130
|
-
# Get context generator for this target type
|
|
131
|
-
gen_context = CONTEXT_GENERATORS.get(target_type, _capture_context)
|
|
132
|
-
|
|
133
|
-
# Build examples
|
|
134
|
-
examples = []
|
|
135
|
-
for page in good_pages:
|
|
136
|
-
task_context = gen_context(page)
|
|
137
|
-
|
|
138
|
-
# Gold output: the actual page body (truncated to keep examples manageable)
|
|
139
|
-
expected_output = page.body[:3000] if len(page.body) > 3000 else page.body
|
|
140
|
-
|
|
141
|
-
example = dspy.Example(
|
|
142
|
-
task_context=task_context,
|
|
143
|
-
expected_output=expected_output,
|
|
144
|
-
# Metadata for the metric
|
|
145
|
-
expected_category=page.category,
|
|
146
|
-
expected_scope=",".join(page.scope),
|
|
147
|
-
expected_slug=page.slug,
|
|
148
|
-
expected_title=page.title,
|
|
149
|
-
page_link_count=str(len(page.links)),
|
|
150
|
-
).with_inputs("task_context")
|
|
151
|
-
|
|
152
|
-
examples.append(example)
|
|
153
|
-
|
|
154
|
-
# Split into train/val
|
|
155
|
-
split_idx = max(1, int(len(examples) * (1 - val_ratio)))
|
|
156
|
-
trainset = examples[:split_idx]
|
|
157
|
-
valset = examples[split_idx:]
|
|
158
|
-
|
|
159
|
-
# Ensure minimum sizes
|
|
160
|
-
if len(trainset) < 2:
|
|
161
|
-
trainset = examples[:max(2, len(examples) // 2)]
|
|
162
|
-
valset = examples[len(trainset):]
|
|
163
|
-
if len(valset) < 2:
|
|
164
|
-
valset = trainset[-2:] # share a few from train if needed
|
|
165
|
-
|
|
166
|
-
return trainset, valset
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
def get_wiki_context(wiki_dir: str) -> str:
|
|
170
|
-
"""Build a wiki context string for the metric/evaluator."""
|
|
171
|
-
stats = get_wiki_stats(wiki_dir)
|
|
172
|
-
pages = load_all_pages(wiki_dir)
|
|
173
|
-
|
|
174
|
-
# Build a brief summary of existing pages for context
|
|
175
|
-
page_summaries = []
|
|
176
|
-
for p in pages[:30]: # Top 30 pages
|
|
177
|
-
first_line = ""
|
|
178
|
-
for line in p.body.split("\n"):
|
|
179
|
-
line = line.strip()
|
|
180
|
-
if line and not line.startswith("#"):
|
|
181
|
-
first_line = line[:100]
|
|
182
|
-
break
|
|
183
|
-
page_summaries.append(f" - [[{p.slug}]] ({p.category}): {p.title}")
|
|
184
|
-
|
|
185
|
-
context = f"""Wiki has {stats['total_pages']} pages across categories: {stats['categories']}.
|
|
186
|
-
Scopes: {', '.join(stats['unique_scopes'][:10])}.
|
|
187
|
-
Avg links/page: {stats['avg_links_per_page']}.
|
|
188
|
-
|
|
189
|
-
Existing pages:
|
|
190
|
-
{chr(10).join(page_summaries)}"""
|
|
191
|
-
|
|
192
|
-
return context
|