@ahkohd/yagami 0.1.10 → 0.1.12

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/src/daemon.ts CHANGED
@@ -646,6 +646,7 @@ const server = http.createServer(async (req, res) => {
646
646
  if (
647
647
  reloading &&
648
648
  !(req.method === "GET" && req.url === "/health") &&
649
+ !(req.method === "GET" && req.url === "/metrics") &&
649
650
  !(req.method === "POST" && req.url === "/stats") &&
650
651
  !(req.method === "POST" && req.url === "/reload") &&
651
652
  !(req.method === "POST" && req.url === "/stop")
@@ -670,6 +671,70 @@ const server = http.createServer(async (req, res) => {
670
671
  });
671
672
  }
672
673
 
674
+ if (req.method === "GET" && req.url === "/metrics") {
675
+ const h = engine.getHealth() as Record<string, unknown>;
676
+ const tokens = (h.tokens || {}) as Record<string, unknown>;
677
+ const tokenCost = (tokens.cost || {}) as Record<string, unknown>;
678
+ const lines = [
679
+ "# HELP yagami_queries_total Total number of queries processed",
680
+ "# TYPE yagami_queries_total counter",
681
+ `yagami_queries_total ${h.queries || 0}`,
682
+ "# HELP yagami_queries_active Currently active queries",
683
+ "# TYPE yagami_queries_active gauge",
684
+ `yagami_queries_active ${h.activeQueries || 0}`,
685
+ "# HELP yagami_cache_hits_total Total cache hits",
686
+ "# TYPE yagami_cache_hits_total counter",
687
+ `yagami_cache_hits_total ${h.cacheHits || 0}`,
688
+ "# HELP yagami_cache_misses_total Total cache misses",
689
+ "# TYPE yagami_cache_misses_total counter",
690
+ `yagami_cache_misses_total ${h.cacheMisses || 0}`,
691
+ "# HELP yagami_cache_hit_rate Cache hit rate ratio",
692
+ "# TYPE yagami_cache_hit_rate gauge",
693
+ `yagami_cache_hit_rate ${h.cacheHitRate || 0}`,
694
+ "# HELP yagami_documents_cached Number of cached documents",
695
+ "# TYPE yagami_documents_cached gauge",
696
+ `yagami_documents_cached ${h.documentsCached || 0}`,
697
+ "# HELP yagami_url_cache_entries Number of URL cache entries",
698
+ "# TYPE yagami_url_cache_entries gauge",
699
+ `yagami_url_cache_entries ${h.urlCacheEntries || 0}`,
700
+ "# HELP yagami_deep_research_tasks Active deep research tasks",
701
+ "# TYPE yagami_deep_research_tasks gauge",
702
+ `yagami_deep_research_tasks ${h.deepResearchTasks || 0}`,
703
+ "# HELP yagami_operation_slots_active Active operation slots",
704
+ "# TYPE yagami_operation_slots_active gauge",
705
+ `yagami_operation_slots_active ${h.operationSlotsActive || 0}`,
706
+ "# HELP yagami_operation_slots_pending Pending operation slots",
707
+ "# TYPE yagami_operation_slots_pending gauge",
708
+ `yagami_operation_slots_pending ${h.operationSlotsPending || 0}`,
709
+ "# HELP yagami_browse_slots_active Active browse slots",
710
+ "# TYPE yagami_browse_slots_active gauge",
711
+ `yagami_browse_slots_active ${h.browseSlotsActive || 0}`,
712
+ "# HELP yagami_browse_slots_pending Pending browse slots",
713
+ "# TYPE yagami_browse_slots_pending gauge",
714
+ `yagami_browse_slots_pending ${h.browseSlotsPending || 0}`,
715
+ "# HELP yagami_tokens_total Total tokens used",
716
+ "# TYPE yagami_tokens_total counter",
717
+ `yagami_tokens_total ${tokens.total || 0}`,
718
+ "# HELP yagami_tokens_input Input tokens used",
719
+ "# TYPE yagami_tokens_input counter",
720
+ `yagami_tokens_input ${tokens.input || 0}`,
721
+ "# HELP yagami_tokens_output Output tokens used",
722
+ "# TYPE yagami_tokens_output counter",
723
+ `yagami_tokens_output ${tokens.output || 0}`,
724
+ "# HELP yagami_uptime_seconds Daemon uptime in seconds",
725
+ "# TYPE yagami_uptime_seconds gauge",
726
+ `yagami_uptime_seconds ${h.uptimeSec || 0}`,
727
+ "",
728
+ ];
729
+ const body = lines.join("\n");
730
+ res.writeHead(200, {
731
+ "content-type": "text/plain; version=0.0.4; charset=utf-8",
732
+ "content-length": Buffer.byteLength(body),
733
+ });
734
+ res.end(body);
735
+ return;
736
+ }
737
+
673
738
  if (req.method === "POST" && req.url === "/stats") {
674
739
  const body = await readJsonBody(req);
675
740
  const includeCacheEntries = Boolean(body.includeCacheEntries);
@@ -229,7 +229,7 @@ export async function tryFetchGitHubRepoContent(
229
229
  }
230
230
 
231
231
  const rawContent = lines.join("\n").trim();
232
- const content = truncateText(rawContent, maxCharacters);
232
+ const content = truncateText(rawContent, maxCharacters, "YAGAMI_MAX_MARKDOWN_CHARS");
233
233
  const truncated = content.length < rawContent.length;
234
234
  const durationMs = Date.now() - startedAt;
235
235
 
@@ -296,10 +296,11 @@ export function categoryProfile(category: unknown): CategoryProfile {
296
296
  return CATEGORY_PROFILES[value] ?? { queryHint: "", includeDomains: [], includeText: [] };
297
297
  }
298
298
 
299
- export function truncateText(text: unknown, maxChars: number): string {
299
+ export function truncateText(text: unknown, maxChars: number, envVar?: string): string {
300
300
  if (typeof text !== "string") return "";
301
301
  if (text.length <= maxChars) return text;
302
- return `${text.slice(0, maxChars)}\n\n[Truncated to ${maxChars} characters]`;
302
+ const hint = envVar ? ` Adjust via ${envVar} env var.` : "";
303
+ return `${text.slice(0, maxChars)}\n\n[Truncated to ${maxChars} characters.${hint}]`;
303
304
  }
304
305
 
305
306
  export function countWords(text: unknown): number {
package/src/engine.ts CHANGED
@@ -749,7 +749,7 @@ export class YagamiEngine {
749
749
  throwIfAborted(abortSignal, "browse aborted");
750
750
 
751
751
  const bodyRaw = await response.text();
752
- const body = truncateText(bodyRaw, this.config.maxHtmlChars);
752
+ const body = truncateText(bodyRaw, this.config.maxHtmlChars, "YAGAMI_MAX_HTML_CHARS");
753
753
  const responseContentType = String(response.headers.get("content-type") || expectedContentType || "text/html")
754
754
  .trim()
755
755
  .toLowerCase();
@@ -1093,7 +1093,7 @@ export class YagamiEngine {
1093
1093
  const parseMs = Date.now() - parseStart;
1094
1094
 
1095
1095
  const formatStart = Date.now();
1096
- const content = truncateText(markdownBody, maxChars);
1096
+ const content = truncateText(markdownBody, maxChars, "YAGAMI_MAX_MARKDOWN_CHARS");
1097
1097
  const sourceTitle = this.extractTitleFromMarkdown(rawMarkdown);
1098
1098
  const sourceTimestamp = this.extractMarkdownFrontmatterField(rawMarkdown, "timestamp");
1099
1099
  const publishedDate = parseIsoDate(sourceTimestamp);
@@ -1175,7 +1175,7 @@ export class YagamiEngine {
1175
1175
 
1176
1176
  const formatStart = Date.now();
1177
1177
  const rawContent = String(extracted.content || "");
1178
- const content = truncateText(rawContent, maxChars);
1178
+ const content = truncateText(rawContent, maxChars, "YAGAMI_MAX_MARKDOWN_CHARS");
1179
1179
 
1180
1180
  const payload = {
1181
1181
  documentId,