@sunub/obsidian-mcp-server 0.3.24 → 0.3.26

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 (101) hide show
  1. package/build/cli/App.d.ts +1 -1
  2. package/build/cli/App.js +150 -100
  3. package/build/cli/App.js.map +1 -1
  4. package/build/cli/AppContainer.d.ts +1 -1
  5. package/build/cli/constants.js +4 -0
  6. package/build/cli/constants.js.map +1 -1
  7. package/build/cli/context/KeypressContext.d.ts +1 -1
  8. package/build/cli/context/KeypressContext.js +3 -0
  9. package/build/cli/context/KeypressContext.js.map +1 -1
  10. package/build/cli/hooks/useDispatcher.js +3 -0
  11. package/build/cli/hooks/useDispatcher.js.map +1 -1
  12. package/build/cli/hooks/useLlmStream/compress.d.ts +16 -0
  13. package/build/cli/hooks/useLlmStream/compress.js +168 -0
  14. package/build/cli/hooks/useLlmStream/compress.js.map +1 -0
  15. package/build/cli/hooks/useLlmStream/llmService.js +12 -5
  16. package/build/cli/hooks/useLlmStream/llmService.js.map +1 -1
  17. package/build/cli/hooks/useLlmStream/markdownUtils.d.ts +6 -0
  18. package/build/cli/hooks/useLlmStream/markdownUtils.js +110 -0
  19. package/build/cli/hooks/useLlmStream/markdownUtils.js.map +1 -0
  20. package/build/cli/hooks/useLlmStream/types.d.ts +189 -0
  21. package/build/cli/hooks/useLlmStream/types.js +41 -1
  22. package/build/cli/hooks/useLlmStream/types.js.map +1 -1
  23. package/build/cli/hooks/useLlmStream/useLlmStream.d.ts +13 -1
  24. package/build/cli/hooks/useLlmStream/useLlmStream.js +75 -22
  25. package/build/cli/hooks/useLlmStream/useLlmStream.js.map +1 -1
  26. package/build/cli/hooks/useRagContext.js +0 -1
  27. package/build/cli/hooks/useRagContext.js.map +1 -1
  28. package/build/cli/hooks/useSlashCommand.d.ts +22 -0
  29. package/build/cli/hooks/useSlashCommand.js +61 -0
  30. package/build/cli/hooks/useSlashCommand.js.map +1 -0
  31. package/build/cli/hooks/useStateAndRef.d.ts +2 -0
  32. package/build/cli/hooks/useStateAndRef.js +18 -0
  33. package/build/cli/hooks/useStateAndRef.js.map +1 -0
  34. package/build/cli/index.js +3 -0
  35. package/build/cli/index.js.map +1 -1
  36. package/build/cli/key/textBuffer/textBuffer.d.ts +1 -0
  37. package/build/cli/key/textBuffer/textBuffer.js +1 -1
  38. package/build/cli/key/textBuffer/textBuffer.js.map +1 -1
  39. package/build/cli/services/InputOffloadService.d.ts +2 -0
  40. package/build/cli/services/InputOffloadService.js +15 -0
  41. package/build/cli/services/InputOffloadService.js.map +1 -1
  42. package/build/cli/types.d.ts +1 -1
  43. package/build/cli/ui/CLILogo.d.ts +1 -1
  44. package/build/cli/ui/HelpCommands.d.ts +1 -1
  45. package/build/cli/ui/HistoryItemDisplay.js +9 -3
  46. package/build/cli/ui/HistoryItemDisplay.js.map +1 -1
  47. package/build/cli/ui/InputPrompt.js +9 -7
  48. package/build/cli/ui/InputPrompt.js.map +1 -1
  49. package/build/cli/ui/LLMErrorComponent.d.ts +1 -1
  50. package/build/cli/ui/LLMHealthChecker.d.ts +1 -1
  51. package/build/cli/ui/LLMStatusLoader.d.ts +1 -1
  52. package/build/cli/ui/MarkdownDisplay.d.ts +1 -1
  53. package/build/cli/ui/SuggestionsDisplay.d.ts +1 -1
  54. package/build/cli/ui/SystemInfoSummaryBox.d.ts +1 -1
  55. package/build/cli/ui/ThinkingIndicator.d.ts +1 -1
  56. package/build/cli/utils/errors.d.ts +14 -0
  57. package/build/cli/utils/errors.js +64 -0
  58. package/build/cli/utils/errors.js.map +1 -0
  59. package/build/cli/utils/retry.d.ts +16 -0
  60. package/build/cli/utils/retry.js +135 -0
  61. package/build/cli/utils/retry.js.map +1 -0
  62. package/build/cli/utils/textUtil.js +0 -6
  63. package/build/cli/utils/textUtil.js.map +1 -1
  64. package/build/config.d.ts +3 -0
  65. package/build/config.js +4 -0
  66. package/build/config.js.map +1 -1
  67. package/build/index.js +18 -5
  68. package/build/index.js.map +1 -1
  69. package/build/shared/utils/debugLogger.js +11 -8
  70. package/build/shared/utils/debugLogger.js.map +1 -1
  71. package/build/tools/vault/params.js +1 -1
  72. package/build/tools/vault/params.js.map +1 -1
  73. package/build/tools/vault/utils/actions/collect_context.js +44 -18
  74. package/build/tools/vault/utils/actions/collect_context.js.map +1 -1
  75. package/build/tools/vault/utils/actions/read.js +39 -9
  76. package/build/tools/vault/utils/actions/read.js.map +1 -1
  77. package/build/utils/Embedder.d.ts +2 -0
  78. package/build/utils/Embedder.js +11 -4
  79. package/build/utils/Embedder.js.map +1 -1
  80. package/build/utils/Indexer.d.ts +3 -1
  81. package/build/utils/Indexer.js +35 -10
  82. package/build/utils/Indexer.js.map +1 -1
  83. package/build/utils/LocalReranker.js +1 -3
  84. package/build/utils/LocalReranker.js.map +1 -1
  85. package/build/utils/RAGIndexer.d.ts +6 -2
  86. package/build/utils/RAGIndexer.js +40 -106
  87. package/build/utils/RAGIndexer.js.map +1 -1
  88. package/build/utils/RerankerClient.d.ts +4 -4
  89. package/build/utils/VaultManger/VaultManager.d.ts +1 -0
  90. package/build/utils/VaultManger/VaultManager.js +84 -25
  91. package/build/utils/VaultManger/VaultManager.js.map +1 -1
  92. package/build/utils/VectorDB.d.ts +2 -1
  93. package/build/utils/VectorDB.js +130 -90
  94. package/build/utils/VectorDB.js.map +1 -1
  95. package/build/utils/worker/WorkerPool.d.ts +15 -0
  96. package/build/utils/worker/WorkerPool.js +89 -0
  97. package/build/utils/worker/WorkerPool.js.map +1 -0
  98. package/build/utils/worker/chunkingWorker.d.ts +11 -0
  99. package/build/utils/worker/chunkingWorker.js +92 -0
  100. package/build/utils/worker/chunkingWorker.js.map +1 -0
  101. package/package.json +1 -3
@@ -0,0 +1,168 @@
1
+ import { callLLMStreaming } from "./llmService.js";
2
+ export const COMPRESSION_CHAR_THRESHOLD = 100_000;
3
+ const TOOL_RESPONSE_CHAR_BUDGET = 80_000;
4
+ const PRESERVE_THRESHOLD = 0.3;
5
+ const COMPRESSION_SYSTEM_PROMPT = `
6
+ 당신은 대화 내역의 핵심 정보를 추출하여 완벽한 상태 문서로 요약하는 상태 저장 관리자입니다.
7
+ 제공되는 이전 대화 기록을 자세히 분석하여, 대화에 등장한 핵심 사실들을 구조화된 <state_snapshot> 문서로 요약해 주십시오.
8
+
9
+ 반드시 다음 내용을 포함하여 작성해야 합니다:
10
+ 1. [최상위 목표]: 현재 사용자와 진행 중인 작업의 궁극적 목표와 현재 수행 단계.
11
+ 2. [핵심 제약 조건]: 사용자가 강조한 환경 조건, 기술적 제한 사항 및 설정 규칙.
12
+ 3. [수집된 사실/정보]: 지금까지 분석하거나 알아낸 핵심 파일 경로, 디렉토리 구조, 주요 함수 및 API 설정 정보.
13
+ 4. [도구 결과 요약]: 실행된 시스템 도구 중 성공하여 중요한 성과를 낸 내용 및 실패하여 얻은 교훈(디버깅 흔적).
14
+
15
+ 쓸데없는 서론이나 대화식 응답("네, 알겠습니다" 등)은 전면 생략하고 오직 <state_snapshot> 데이터 구조만 명확히 출력하십시오.
16
+ `;
17
+ /**
18
+ * 개별 텍스트 줄 수가 한도를 초과할 때 뒷부분 30줄만 보존하는 헬퍼 함수
19
+ */
20
+ function truncateTextLines(content, limit = 30) {
21
+ const lines = content.split("\n");
22
+ if (lines.length <= limit)
23
+ return content;
24
+ const truncated = lines.slice(-limit);
25
+ return `[... 대용량 도구 출력이 너무 길어 앞부분이 생략되었습니다 ...]\n${truncated.join("\n")}`;
26
+ }
27
+ /**
28
+ * 역방향 누적 버짓 전략:
29
+ * 최근 도구 호출 결과는 중요하므로 보존하되, 오래된 대형 툴 결과물은 순차적으로 잘라내어 컨텍스트를 확보합니다.
30
+ */
31
+ export function truncateToolResponsesToBudget(history) {
32
+ let accumulatedToolChars = 0;
33
+ const resultHistory = [];
34
+ // 최신 메시지부터 역순으로 탐색
35
+ for (let i = history.length - 1; i >= 0; i--) {
36
+ const msg = history[i];
37
+ if (msg.role === "tool") {
38
+ const charCount = msg.content.length;
39
+ if (accumulatedToolChars + charCount > TOOL_RESPONSE_CHAR_BUDGET) {
40
+ // 예산을 초과하면 마지막 30줄만 남기고 절사
41
+ const truncatedContent = truncateTextLines(msg.content);
42
+ resultHistory.unshift({
43
+ ...msg,
44
+ content: truncatedContent,
45
+ });
46
+ accumulatedToolChars += truncatedContent.length;
47
+ }
48
+ else {
49
+ resultHistory.unshift(msg);
50
+ accumulatedToolChars += charCount;
51
+ }
52
+ }
53
+ else {
54
+ resultHistory.unshift(msg);
55
+ }
56
+ }
57
+ return resultHistory;
58
+ }
59
+ /**
60
+ * 대화 내역 중 요약 압축할 지점과 보존할 지점을 분할하는 인덱스를 찾습니다.
61
+ * 흐름을 해치지 않도록 반드시 'user'가 질문하기 직전 지점을 기점으로 분할합니다.
62
+ */
63
+ export function findCompressSplitPoint(contents, fraction) {
64
+ if (fraction <= 0 || fraction >= 1) {
65
+ throw new Error("Fraction must be between 0 and 1");
66
+ }
67
+ const charCounts = contents.map((c) => JSON.stringify(c).length);
68
+ const totalCharCount = charCounts.reduce((a, b) => a + b, 0);
69
+ const targetCharCount = totalCharCount * fraction;
70
+ let lastSplitPoint = 0;
71
+ let cumulativeCharCount = 0;
72
+ for (let i = 0; i < contents.length; i++) {
73
+ const content = contents[i];
74
+ // 툴 응답이나 어시스턴트의 중간 연산 과정이 아닌 일반 'user' 시작 턴을 안전 분할점으로 지정
75
+ if (content.role === "user") {
76
+ if (cumulativeCharCount >= targetCharCount) {
77
+ return i;
78
+ }
79
+ lastSplitPoint = i;
80
+ }
81
+ cumulativeCharCount += charCounts[i];
82
+ }
83
+ return lastSplitPoint;
84
+ }
85
+ /**
86
+ * 1차 스냅샷 요약 및 2차 자가 보정 검증을 통해 핵심 데이터 손실을 차단합니다.
87
+ */
88
+ export async function compressHistory(messages, abortSignal) {
89
+ try {
90
+ const totalLength = messages.reduce((acc, m) => acc + JSON.stringify(m).length, 0);
91
+ // 임계치를 넘지 않았거나 압축을 하기에 대화 내역이 너무 짧은 경우 생략
92
+ if (totalLength < COMPRESSION_CHAR_THRESHOLD || messages.length < 5) {
93
+ return messages;
94
+ }
95
+ // 1단계: 대용량 툴 결과물 역방향 예산 절사 적용
96
+ const truncatedHistory = truncateToolResponsesToBudget(messages);
97
+ // 2단계: 최신 30% 보존을 위해 분할선 인덱스 탐색
98
+ const splitPoint = findCompressSplitPoint(truncatedHistory, 1 - PRESERVE_THRESHOLD);
99
+ const historyToCompress = truncatedHistory.slice(0, splitPoint);
100
+ const historyToKeep = truncatedHistory.slice(splitPoint);
101
+ if (historyToCompress.length === 0) {
102
+ return messages;
103
+ }
104
+ // 기존에 생성된 스냅샷이 이미 이전 히스토리에 존재하는지 체크
105
+ const hasPreviousSnapshot = historyToCompress.some((m) => m.content.includes("<state_snapshot>"));
106
+ const anchorInstruction = hasPreviousSnapshot
107
+ ? "대화 기록 내에 이미 이전 <state_snapshot>이 존재합니다. 이전 스냅샷에 기록된 아직 유효한 중요 세부 사항 및 제약 조건을 반드시 새로 생성할 스냅샷에 완전히 계승·병합하고 최근 사건들을 덧붙여 주십시오."
108
+ : "제공된 대화 내역을 바탕으로 완전히 새로운 <state_snapshot>을 생성해 주십시오.";
109
+ // 3단계: 1차 요약 상태 스냅샷(<state_snapshot>) 생성
110
+ const firstSummarizeMessages = [
111
+ { role: "system", content: COMPRESSION_SYSTEM_PROMPT },
112
+ ...historyToCompress,
113
+ {
114
+ role: "user",
115
+ content: `${anchorInstruction}\n이전 대화 기록을 분석하여 보존해야 할 핵심 정보(파일 경로, 진행 상태, 제약 조건 등)를 망라한 새로운 <state_snapshot>을 상세히 작성해 주십시오.`,
116
+ },
117
+ ];
118
+ let firstSummary = "";
119
+ for await (const event of callLLMStreaming(firstSummarizeMessages, undefined, false, abortSignal)) {
120
+ if (event.type === "content") {
121
+ firstSummary += event.chunk;
122
+ }
123
+ }
124
+ firstSummary = firstSummary.trim();
125
+ if (!firstSummary) {
126
+ return messages; // 요약본 생성 실패 시 원본 그대로 보존
127
+ }
128
+ // 4단계: 2차 자가 보정 검증
129
+ const verificationMessages = [
130
+ { role: "system", content: COMPRESSION_SYSTEM_PROMPT },
131
+ ...historyToCompress,
132
+ { role: "assistant", content: firstSummary },
133
+ {
134
+ role: "user",
135
+ content: "방금 귀하가 작성한 <state_snapshot>에 대화 기록에서 언급된 핵심적인 파일 경로, 코드 함수, 사용자 제약 조건 또는 도구의 성공 결과 중 누락된 부분이 있습니까? 유실되거나 부정확한 정보가 있다면 해당 내용을 보완하여 한 단계 향상된 최종 <state_snapshot> 문서를 새로 작성해 주십시오. 누락된 세부 사항이 전혀 없다면 방금 작성한 스냅샷을 그대로 다시 출력해 주십시오.",
136
+ },
137
+ ];
138
+ let finalSummary = "";
139
+ for await (const event of callLLMStreaming(verificationMessages, undefined, false, abortSignal)) {
140
+ if (event.type === "content") {
141
+ finalSummary += event.chunk;
142
+ }
143
+ }
144
+ finalSummary = finalSummary.trim() || firstSummary;
145
+ // 5단계: 압축된 스냅샷을 포함하여 새로운 히스토리 구성
146
+ const newHistory = [
147
+ {
148
+ role: "user",
149
+ content: `이전 작업 요약:\n\n${finalSummary}`,
150
+ },
151
+ {
152
+ role: "assistant",
153
+ content: "요약된 이전 작업 상태 스냅샷을 파악했습니다. 이 정보와 남아 있는 최근 대화 맥락을 기반으로 작업을 이어서 진행하겠습니다.",
154
+ },
155
+ ...historyToKeep,
156
+ ];
157
+ // 압축 결과물의 텍스트 볼륨이 원래보다 부풀려진 예외 케이스 방지
158
+ const newTotalLength = newHistory.reduce((acc, m) => acc + JSON.stringify(m).length, 0);
159
+ if (newTotalLength >= totalLength) {
160
+ return messages; // 압축 효과가 없거나 부풀어 오른 경우 롤백
161
+ }
162
+ return newHistory;
163
+ }
164
+ catch {
165
+ return messages;
166
+ }
167
+ }
168
+ //# sourceMappingURL=compress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compress.js","sourceRoot":"","sources":["../../../../src/cli/hooks/useLlmStream/compress.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAGnD,MAAM,CAAC,MAAM,0BAA0B,GAAG,OAAO,CAAC;AAElD,MAAM,yBAAyB,GAAG,MAAM,CAAC;AACzC,MAAM,kBAAkB,GAAG,GAAG,CAAC;AAC/B,MAAM,yBAAyB,GAAG;;;;;;;;;;;CAWjC,CAAC;AAEF;;GAEG;AACH,SAAS,iBAAiB,CAAC,OAAe,EAAE,KAAK,GAAG,EAAE;IACrD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClC,IAAI,KAAK,CAAC,MAAM,IAAI,KAAK;QAAE,OAAO,OAAO,CAAC;IAC1C,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;IACtC,OAAO,4CAA4C,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AAC3E,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,6BAA6B,CAC5C,OAA8B;IAE9B,IAAI,oBAAoB,GAAG,CAAC,CAAC;IAC7B,MAAM,aAAa,GAA0B,EAAE,CAAC;IAEhD,mBAAmB;IACnB,KAAK,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC9C,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QAEvB,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACzB,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;YACrC,IAAI,oBAAoB,GAAG,SAAS,GAAG,yBAAyB,EAAE,CAAC;gBAClE,2BAA2B;gBAC3B,MAAM,gBAAgB,GAAG,iBAAiB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBACxD,aAAa,CAAC,OAAO,CAAC;oBACrB,GAAG,GAAG;oBACN,OAAO,EAAE,gBAAgB;iBACzB,CAAC,CAAC;gBACH,oBAAoB,IAAI,gBAAgB,CAAC,MAAM,CAAC;YACjD,CAAC;iBAAM,CAAC;gBACP,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBAC3B,oBAAoB,IAAI,SAAS,CAAC;YACnC,CAAC;QACF,CAAC;aAAM,CAAC;YACP,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC5B,CAAC;IACF,CAAC;IAED,OAAO,aAAa,CAAC;AACtB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CACrC,QAA+B,EAC/B,QAAgB;IAEhB,IAAI,QAAQ,IAAI,CAAC,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACrD,CAAC;IAED,MAAM,UAAU,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IACjE,MAAM,cAAc,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7D,MAAM,eAAe,GAAG,cAAc,GAAG,QAAQ,CAAC;IAElD,IAAI,cAAc,GAAG,CAAC,CAAC;IACvB,IAAI,mBAAmB,GAAG,CAAC,CAAC;IAE5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1C,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;QAC5B,yDAAyD;QACzD,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC7B,IAAI,mBAAmB,IAAI,eAAe,EAAE,CAAC;gBAC5C,OAAO,CAAC,CAAC;YACV,CAAC;YACD,cAAc,GAAG,CAAC,CAAC;QACpB,CAAC;QACD,mBAAmB,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;IACtC,CAAC;IAED,OAAO,cAAc,CAAC;AACvB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACpC,QAA+B,EAC/B,WAAyB;IAEzB,IAAI,CAAC;QACJ,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAClC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,EAC1C,CAAC,CACD,CAAC;QAEF,0CAA0C;QAC1C,IAAI,WAAW,GAAG,0BAA0B,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrE,OAAO,QAAQ,CAAC;QACjB,CAAC;QAED,8BAA8B;QAC9B,MAAM,gBAAgB,GAAG,6BAA6B,CAAC,QAAQ,CAAC,CAAC;QAEjE,gCAAgC;QAChC,MAAM,UAAU,GAAG,sBAAsB,CACxC,gBAAgB,EAChB,CAAC,GAAG,kBAAkB,CACtB,CAAC;QAEF,MAAM,iBAAiB,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;QAChE,MAAM,aAAa,GAAG,gBAAgB,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAEzD,IAAI,iBAAiB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACpC,OAAO,QAAQ,CAAC;QACjB,CAAC;QAED,oCAAoC;QACpC,MAAM,mBAAmB,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CACxD,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CACtC,CAAC;QAEF,MAAM,iBAAiB,GAAG,mBAAmB;YAC5C,CAAC,CAAC,4HAA4H;YAC9H,CAAC,CAAC,qDAAqD,CAAC;QAEzD,yCAAyC;QACzC,MAAM,sBAAsB,GAA0B;YACrD,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,yBAAyB,EAAE;YACtD,GAAG,iBAAiB;YACpB;gBACC,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,GAAG,iBAAiB,+FAA+F;aAC5H;SACD,CAAC;QAEF,IAAI,YAAY,GAAG,EAAE,CAAC;QACtB,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,gBAAgB,CACzC,sBAAsB,EACtB,SAAS,EACT,KAAK,EACL,WAAW,CACX,EAAE,CAAC;YACH,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;gBAC9B,YAAY,IAAI,KAAK,CAAC,KAAK,CAAC;YAC7B,CAAC;QACF,CAAC;QAED,YAAY,GAAG,YAAY,CAAC,IAAI,EAAE,CAAC;QACnC,IAAI,CAAC,YAAY,EAAE,CAAC;YACnB,OAAO,QAAQ,CAAC,CAAC,wBAAwB;QAC1C,CAAC;QAED,mBAAmB;QACnB,MAAM,oBAAoB,GAA0B;YACnD,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,yBAAyB,EAAE;YACtD,GAAG,iBAAiB;YACpB,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,YAAY,EAAE;YAC5C;gBACC,IAAI,EAAE,MAAM;gBACZ,OAAO,EACN,gOAAgO;aACjO;SACD,CAAC;QAEF,IAAI,YAAY,GAAG,EAAE,CAAC;QACtB,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,gBAAgB,CACzC,oBAAoB,EACpB,SAAS,EACT,KAAK,EACL,WAAW,CACX,EAAE,CAAC;YACH,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;gBAC9B,YAAY,IAAI,KAAK,CAAC,KAAK,CAAC;YAC7B,CAAC;QACF,CAAC;QAED,YAAY,GAAG,YAAY,CAAC,IAAI,EAAE,IAAI,YAAY,CAAC;QAEnD,iCAAiC;QACjC,MAAM,UAAU,GAA0B;YACzC;gBACC,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,gBAAgB,YAAY,EAAE;aACvC;YACD;gBACC,IAAI,EAAE,WAAW;gBACjB,OAAO,EACN,uEAAuE;aACxE;YACD,GAAG,aAAa;SAChB,CAAC;QAEF,sCAAsC;QACtC,MAAM,cAAc,GAAG,UAAU,CAAC,MAAM,CACvC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,EAC1C,CAAC,CACD,CAAC;QACF,IAAI,cAAc,IAAI,WAAW,EAAE,CAAC;YACnC,OAAO,QAAQ,CAAC,CAAC,0BAA0B;QAC5C,CAAC;QAED,OAAO,UAAU,CAAC;IACnB,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,QAAQ,CAAC;IACjB,CAAC;AACF,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { cleanMessagesForNoTools } from "../../hooks/useLlmStream/utils.js";
2
+ import { retryWithBackoff } from "../../../cli/utils/retry.js";
2
3
  import state from "../../../config.js";
3
4
  import { debugLogger } from "../../../shared/index.js";
4
5
  let toolCallingSupportedCache = null;
@@ -14,12 +15,16 @@ export async function* callLLMStreaming(messages, tools, allowFallback = true, s
14
15
  body["tools"] = effectiveTools;
15
16
  body["tool_choice"] = "auto";
16
17
  }
17
- const response = await fetch(url, {
18
+ const timeoutSignal = AbortSignal.timeout(state.llmTimeoutMs);
19
+ const combinedSignal = signal
20
+ ? AbortSignal.any([signal, timeoutSignal])
21
+ : timeoutSignal;
22
+ const response = await retryWithBackoff(async () => fetch(url, {
18
23
  method: "POST",
19
24
  headers: { "Content-Type": "application/json" },
20
25
  body: JSON.stringify(body),
21
- signal,
22
- });
26
+ signal: combinedSignal,
27
+ }), { signal: combinedSignal });
23
28
  if (!response.ok) {
24
29
  if (response.status >= 500 &&
25
30
  effectiveTools &&
@@ -44,15 +49,17 @@ export async function* callLLMStreaming(messages, tools, allowFallback = true, s
44
49
  toolCallingSupportedCache = true;
45
50
  }
46
51
  const reader = response.body?.getReader();
47
- if (!reader)
52
+ if (!reader) {
48
53
  throw new Error("Response body is null");
54
+ }
49
55
  const decoder = new TextDecoder();
50
56
  let buffer = "";
51
57
  const toolCallAccum = new Map();
52
58
  while (true) {
53
59
  const { done, value } = await reader.read();
54
- if (done)
60
+ if (done) {
55
61
  break;
62
+ }
56
63
  buffer += decoder.decode(value, { stream: true });
57
64
  const lines = buffer.split("\n");
58
65
  buffer = lines.pop() ?? "";
@@ -1 +1 @@
1
- {"version":3,"file":"llmService.js","sourceRoot":"","sources":["../../../../src/cli/hooks/useLlmStream/llmService.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"llmService.js","sourceRoot":"","sources":["../../../../src/cli/hooks/useLlmStream/llmService.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAC3E,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,MAAM,aAAa,CAAC;AAChC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,IAAI,yBAAyB,GAAmB,IAAI,CAAC;AAErD,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,gBAAgB,CACtC,QAA+B,EAC/B,KAAoB,EACpB,aAAa,GAAG,IAAI,EACpB,MAAoB;IAEpB,MAAM,GAAG,GAAG,GAAG,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,sBAAsB,CAAC;IAExE,MAAM,cAAc,GACnB,yBAAyB,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC;IAEzD,MAAM,IAAI,GAA4B;QACrC,KAAK,EAAE,KAAK,CAAC,YAAY;QACzB,QAAQ;QACR,MAAM,EAAE,IAAI;KACZ,CAAC;IACF,IAAI,cAAc,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACjD,IAAI,CAAC,OAAO,CAAC,GAAG,cAAc,CAAC;QAC/B,IAAI,CAAC,aAAa,CAAC,GAAG,MAAM,CAAC;IAC9B,CAAC;IAED,MAAM,aAAa,GAAG,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IAC9D,MAAM,cAAc,GAAG,MAAM;QAC5B,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;QAC1C,CAAC,CAAC,aAAa,CAAC;IAEjB,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CACtC,KAAK,IAAI,EAAE,CACV,KAAK,CAAC,GAAG,EAAE;QACV,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;QAC1B,MAAM,EAAE,cAAc;KACtB,CAAC,EACH,EAAE,MAAM,EAAE,cAAc,EAAE,CAC1B,CAAC;IAEF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QAClB,IACC,QAAQ,CAAC,MAAM,IAAI,GAAG;YACtB,cAAc;YACd,cAAc,CAAC,MAAM,GAAG,CAAC;YACzB,aAAa,EACZ,CAAC;YACF,MAAM,eAAe,GAAG,QAAQ,CAAC,IAAI,CACpC,CAAC,CAAC,EAAE,EAAE,CACL,CAAC,CAAC,IAAI,KAAK,MAAM;gBACjB,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,IAAI,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CACpE,CAAC;YACF,IAAI,CAAC,eAAe,EAAE,CAAC;gBACtB,yBAAyB,GAAG,KAAK,CAAC;YACnC,CAAC;YACD,WAAW,CAAC,IAAI,CACf,eAAe;gBACd,CAAC,CAAC,wEAAwE;gBAC1E,CAAC,CAAC,2EAA2E,CAC9E,CAAC;YACF,MAAM,aAAa,GAAG,uBAAuB,CAAC,QAAQ,CAAC,CAAC;YACxD,KAAK,CAAC,CAAC,gBAAgB,CAAC,aAAa,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;YACzD,OAAO;QACR,CAAC;QACD,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,kBAAkB,QAAQ,CAAC,MAAM,MAAM,SAAS,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,IAAI,cAAc,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACjD,yBAAyB,GAAG,IAAI,CAAC;IAClC,CAAC;IAED,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC;IAC1C,IAAI,CAAC,MAAM,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAC1C,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAClC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,MAAM,aAAa,GAAG,IAAI,GAAG,EAG1B,CAAC;IAEJ,OAAO,IAAI,EAAE,CAAC;QACb,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QAC5C,IAAI,IAAI,EAAE,CAAC;YACV,MAAM;QACP,CAAC;QAED,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QAClD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACjC,MAAM,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;QAE3B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YAC1B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;YACnD,IAAI,CAAC,OAAO,IAAI,OAAO,KAAK,QAAQ;gBAAE,SAAS;YAE/C,IAAI,CAAC;gBACJ,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAYhC,CAAC;gBAEF,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;gBACnC,IAAI,CAAC,MAAM;oBAAE,SAAS;gBAEtB,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;gBAE3B,IAAI,KAAK,EAAE,OAAO,EAAE,CAAC;oBACpB,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC;gBACjD,CAAC;gBAED,IAAI,KAAK,EAAE,UAAU,EAAE,CAAC;oBACvB,KAAK,MAAM,EAAE,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;wBACnC,MAAM,QAAQ,GAAG,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;wBAC7C,IAAI,CAAC,QAAQ,EAAE,CAAC;4BACf,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE;gCAC3B,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE;gCACf,IAAI,EAAE,EAAE,CAAC,QAAQ,EAAE,IAAI,IAAI,EAAE;gCAC7B,SAAS,EAAE,EAAE,CAAC,QAAQ,EAAE,SAAS,IAAI,EAAE;6BACvC,CAAC,CAAC;wBACJ,CAAC;6BAAM,CAAC;4BACP,IAAI,EAAE,CAAC,EAAE;gCAAE,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;4BAC/B,IAAI,EAAE,CAAC,QAAQ,EAAE,IAAI;gCAAE,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC;4BACzD,IAAI,EAAE,CAAC,QAAQ,EAAE,SAAS;gCACzB,QAAQ,CAAC,SAAS,IAAI,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC;wBAC9C,CAAC;oBACF,CAAC;gBACF,CAAC;gBAED,MAAM,iBAAiB,GACtB,CAAC,MAAM,CAAC,aAAa,KAAK,YAAY;oBACrC,MAAM,CAAC,aAAa,KAAK,MAAM,CAAC;oBACjC,aAAa,CAAC,IAAI,GAAG,CAAC,CAAC;gBAExB,IAAI,iBAAiB,EAAE,CAAC;oBACvB,MAAM,KAAK,GAAe,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,CAAC;yBAC3D,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;yBACzB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;wBACjB,EAAE,EAAE,EAAE,CAAC,EAAE;wBACT,IAAI,EAAE,UAAmB;wBACzB,QAAQ,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC,SAAS,EAAE;qBACpD,CAAC,CAAC,CAAC;oBACL,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;oBACpC,OAAO;gBACR,CAAC;YACF,CAAC;YAAC,OAAO,EAAE,EAAE,CAAC,CAAA,CAAC;QAChB,CAAC;IACF,CAAC;AACF,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ export declare const findLastSafeSplitPoint: (content: string) => number;
@@ -0,0 +1,110 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ /*
7
+ **Background & Purpose:**
8
+
9
+ The `findSafeSplitPoint` function is designed to address the challenge of displaying or processing large, potentially streaming, pieces of Markdown text. When content (e.g., from an LLM like Gemini) arrives in chunks or grows too large for a single display unit (like a message bubble), it needs to be split. A naive split (e.g., just at a character limit) can break Markdown formatting, especially critical for multi-line elements like code blocks, lists, or blockquotes, leading to incorrect rendering.
10
+
11
+ This function aims to find an *intelligent* or "safe" index within the provided `content` string at which to make such a split, prioritizing the preservation of Markdown integrity.
12
+
13
+ **Key Expectations & Behavior (Prioritized):**
14
+
15
+ 1. **No Split if Short Enough:**
16
+ * If `content.length` is less than or equal to `idealMaxLength`, the function should return `content.length` (indicating no split is necessary for length reasons).
17
+
18
+ 2. **Code Block Integrity (Highest Priority for Safety):**
19
+ * The function must try to avoid splitting *inside* a fenced code block (i.e., between ` ``` ` and ` ``` `).
20
+ * If `idealMaxLength` falls within a code block:
21
+ * The function will attempt to return an index that splits the content *before* the start of that code block.
22
+ * If a code block starts at the very beginning of the `content` and `idealMaxLength` falls within it (meaning the block itself is too long for the first chunk), the function might return `0`. This effectively makes the first chunk empty, pushing the entire oversized code block to the second part of the split.
23
+ * When considering splits near code blocks, the function prefers to keep the entire code block intact in one of the resulting chunks.
24
+
25
+ 3. **Markdown-Aware Newline Splitting (If Not Governed by Code Block Logic):**
26
+ * If `idealMaxLength` does not fall within a code block (or after code block considerations have been made), the function will look for natural break points by scanning backwards from `idealMaxLength`:
27
+ * **Paragraph Breaks:** It prioritizes splitting after a double newline (`\n\n`), as this typically signifies the end of a paragraph or a block-level element.
28
+ * **Single Line Breaks:** If no double newline is found in a suitable range, it will look for a single newline (`\n`).
29
+ * Any newline chosen as a split point must also not be inside a code block.
30
+
31
+ 4. **Fall back to `idealMaxLength`:**
32
+ * If no "safer" split point (respecting code blocks or finding suitable newlines) is identified before or at `idealMaxLength`, and `idealMaxLength` itself is not determined to be an unsafe split point (e.g., inside a code block), the function may return a length larger than `idealMaxLength`, again it CANNOT break markdown formatting. This could happen with very long lines of text without Markdown block structures or newlines.
33
+
34
+ **In essence, `findSafeSplitPoint` tries to be a good Markdown citizen when forced to divide content, preferring structural boundaries over arbitrary character limits, with a strong emphasis on not corrupting code blocks.**
35
+ */
36
+ /**
37
+ * Checks if a given character index within a string is inside a fenced (```) code block.
38
+ * @param content The full string content.
39
+ * @param indexToTest The character index to test.
40
+ * @returns True if the index is inside a code block's content, false otherwise.
41
+ */
42
+ const isIndexInsideCodeBlock = (content, indexToTest) => {
43
+ let fenceCount = 0;
44
+ let searchPos = 0;
45
+ while (searchPos < content.length) {
46
+ const nextFence = content.indexOf("```", searchPos);
47
+ if (nextFence === -1 || nextFence >= indexToTest) {
48
+ break;
49
+ }
50
+ fenceCount++;
51
+ searchPos = nextFence + 3;
52
+ }
53
+ return fenceCount % 2 === 1;
54
+ };
55
+ /**
56
+ * Finds the starting index of the code block that encloses the given index.
57
+ * Returns -1 if the index is not inside a code block.
58
+ * @param content The markdown content.
59
+ * @param index The index to check.
60
+ * @returns Start index of the enclosing code block or -1.
61
+ */
62
+ const findEnclosingCodeBlockStart = (content, index) => {
63
+ if (!isIndexInsideCodeBlock(content, index)) {
64
+ return -1;
65
+ }
66
+ let currentSearchPos = 0;
67
+ while (currentSearchPos < index) {
68
+ const blockStartIndex = content.indexOf("```", currentSearchPos);
69
+ if (blockStartIndex === -1 || blockStartIndex >= index) {
70
+ break;
71
+ }
72
+ const blockEndIndex = content.indexOf("```", blockStartIndex + 3);
73
+ if (blockStartIndex < index) {
74
+ if (blockEndIndex === -1 || index < blockEndIndex + 3) {
75
+ return blockStartIndex;
76
+ }
77
+ }
78
+ if (blockEndIndex === -1)
79
+ break;
80
+ currentSearchPos = blockEndIndex + 3;
81
+ }
82
+ return -1;
83
+ };
84
+ export const findLastSafeSplitPoint = (content) => {
85
+ const enclosingBlockStart = findEnclosingCodeBlockStart(content, content.length);
86
+ if (enclosingBlockStart !== -1) {
87
+ // The end of the content is contained in a code block. Split right before.
88
+ return enclosingBlockStart;
89
+ }
90
+ // Search for the last double newline (\n\n) not in a code block.
91
+ let searchStartIndex = content.length;
92
+ while (searchStartIndex >= 0) {
93
+ const dnlIndex = content.lastIndexOf("\n\n", searchStartIndex);
94
+ if (dnlIndex === -1) {
95
+ // No more double newlines found.
96
+ break;
97
+ }
98
+ const potentialSplitPoint = dnlIndex + 2;
99
+ if (!isIndexInsideCodeBlock(content, potentialSplitPoint)) {
100
+ return potentialSplitPoint;
101
+ }
102
+ // If potentialSplitPoint was inside a code block,
103
+ // the next search should start *before* the \n\n we just found to ensure progress.
104
+ searchStartIndex = dnlIndex - 1;
105
+ }
106
+ // If no safe double newline is found, return content.length
107
+ // to keep the entire content as one piece.
108
+ return content.length;
109
+ };
110
+ //# sourceMappingURL=markdownUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdownUtils.js","sourceRoot":"","sources":["../../../../src/cli/hooks/useLlmStream/markdownUtils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6BE;AAEF;;;;;GAKG;AACH,MAAM,sBAAsB,GAAG,CAC9B,OAAe,EACf,WAAmB,EACT,EAAE;IACZ,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,OAAO,SAAS,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;QACnC,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;QACpD,IAAI,SAAS,KAAK,CAAC,CAAC,IAAI,SAAS,IAAI,WAAW,EAAE,CAAC;YAClD,MAAM;QACP,CAAC;QACD,UAAU,EAAE,CAAC;QACb,SAAS,GAAG,SAAS,GAAG,CAAC,CAAC;IAC3B,CAAC;IACD,OAAO,UAAU,GAAG,CAAC,KAAK,CAAC,CAAC;AAC7B,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,2BAA2B,GAAG,CACnC,OAAe,EACf,KAAa,EACJ,EAAE;IACX,IAAI,CAAC,sBAAsB,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC;QAC7C,OAAO,CAAC,CAAC,CAAC;IACX,CAAC;IACD,IAAI,gBAAgB,GAAG,CAAC,CAAC;IACzB,OAAO,gBAAgB,GAAG,KAAK,EAAE,CAAC;QACjC,MAAM,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAC;QACjE,IAAI,eAAe,KAAK,CAAC,CAAC,IAAI,eAAe,IAAI,KAAK,EAAE,CAAC;YACxD,MAAM;QACP,CAAC;QACD,MAAM,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,eAAe,GAAG,CAAC,CAAC,CAAC;QAClE,IAAI,eAAe,GAAG,KAAK,EAAE,CAAC;YAC7B,IAAI,aAAa,KAAK,CAAC,CAAC,IAAI,KAAK,GAAG,aAAa,GAAG,CAAC,EAAE,CAAC;gBACvD,OAAO,eAAe,CAAC;YACxB,CAAC;QACF,CAAC;QACD,IAAI,aAAa,KAAK,CAAC,CAAC;YAAE,MAAM;QAChC,gBAAgB,GAAG,aAAa,GAAG,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,CAAC,CAAC,CAAC;AACX,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,OAAe,EAAE,EAAE;IACzD,MAAM,mBAAmB,GAAG,2BAA2B,CACtD,OAAO,EACP,OAAO,CAAC,MAAM,CACd,CAAC;IACF,IAAI,mBAAmB,KAAK,CAAC,CAAC,EAAE,CAAC;QAChC,2EAA2E;QAC3E,OAAO,mBAAmB,CAAC;IAC5B,CAAC;IAED,iEAAiE;IACjE,IAAI,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC;IACtC,OAAO,gBAAgB,IAAI,CAAC,EAAE,CAAC;QAC9B,MAAM,QAAQ,GAAG,OAAO,CAAC,WAAW,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;QAC/D,IAAI,QAAQ,KAAK,CAAC,CAAC,EAAE,CAAC;YACrB,iCAAiC;YACjC,MAAM;QACP,CAAC;QAED,MAAM,mBAAmB,GAAG,QAAQ,GAAG,CAAC,CAAC;QACzC,IAAI,CAAC,sBAAsB,CAAC,OAAO,EAAE,mBAAmB,CAAC,EAAE,CAAC;YAC3D,OAAO,mBAAmB,CAAC;QAC5B,CAAC;QAED,kDAAkD;QAClD,mFAAmF;QACnF,gBAAgB,GAAG,QAAQ,GAAG,CAAC,CAAC;IACjC,CAAC;IAED,4DAA4D;IAC5D,2CAA2C;IAC3C,OAAO,OAAO,CAAC,MAAM,CAAC;AACvB,CAAC,CAAC"}
@@ -1,3 +1,4 @@
1
+ import z from "zod";
1
2
  export interface OpenAITool {
2
3
  type: "function";
3
4
  function: {
@@ -36,3 +37,191 @@ export type StreamEvent = {
36
37
  type: "tool_calls";
37
38
  calls: ToolCall[];
38
39
  };
40
+ export declare const LLMResponseSchema: z.ZodObject<{
41
+ id: z.ZodString;
42
+ object: z.ZodString;
43
+ created: z.ZodNumber;
44
+ model: z.ZodString;
45
+ system_fingerprint: z.ZodOptional<z.ZodString>;
46
+ choices: z.ZodArray<z.ZodObject<{
47
+ index: z.ZodNumber;
48
+ finish_reason: z.ZodOptional<z.ZodNullable<z.ZodString>>;
49
+ delta: z.ZodObject<{
50
+ role: z.ZodOptional<z.ZodString>;
51
+ content: z.ZodOptional<z.ZodString>;
52
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
53
+ role: z.ZodOptional<z.ZodString>;
54
+ content: z.ZodOptional<z.ZodString>;
55
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
56
+ role: z.ZodOptional<z.ZodString>;
57
+ content: z.ZodOptional<z.ZodString>;
58
+ }, z.ZodTypeAny, "passthrough">>;
59
+ }, "strip", z.ZodTypeAny, {
60
+ index: number;
61
+ delta: {
62
+ content?: string | undefined;
63
+ role?: string | undefined;
64
+ } & {
65
+ [k: string]: unknown;
66
+ };
67
+ finish_reason?: string | null | undefined;
68
+ }, {
69
+ index: number;
70
+ delta: {
71
+ content?: string | undefined;
72
+ role?: string | undefined;
73
+ } & {
74
+ [k: string]: unknown;
75
+ };
76
+ finish_reason?: string | null | undefined;
77
+ }>, "many">;
78
+ timings: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNumber>>;
79
+ }, "strip", z.ZodTypeAny, {
80
+ object: string;
81
+ id: string;
82
+ choices: {
83
+ index: number;
84
+ delta: {
85
+ content?: string | undefined;
86
+ role?: string | undefined;
87
+ } & {
88
+ [k: string]: unknown;
89
+ };
90
+ finish_reason?: string | null | undefined;
91
+ }[];
92
+ model: string;
93
+ created: number;
94
+ system_fingerprint?: string | undefined;
95
+ timings?: Record<string, number> | undefined;
96
+ }, {
97
+ object: string;
98
+ id: string;
99
+ choices: {
100
+ index: number;
101
+ delta: {
102
+ content?: string | undefined;
103
+ role?: string | undefined;
104
+ } & {
105
+ [k: string]: unknown;
106
+ };
107
+ finish_reason?: string | null | undefined;
108
+ }[];
109
+ model: string;
110
+ created: number;
111
+ system_fingerprint?: string | undefined;
112
+ timings?: Record<string, number> | undefined;
113
+ }>;
114
+ export declare const SSEMessageSchema: z.ZodObject<{
115
+ data: z.ZodPipeline<z.ZodEffects<z.ZodString, any, string>, z.ZodUnion<[z.ZodObject<{
116
+ isDone: z.ZodLiteral<true>;
117
+ }, "strip", z.ZodTypeAny, {
118
+ isDone: true;
119
+ }, {
120
+ isDone: true;
121
+ }>, z.ZodObject<{
122
+ id: z.ZodString;
123
+ object: z.ZodString;
124
+ created: z.ZodNumber;
125
+ model: z.ZodString;
126
+ system_fingerprint: z.ZodOptional<z.ZodString>;
127
+ choices: z.ZodArray<z.ZodObject<{
128
+ index: z.ZodNumber;
129
+ finish_reason: z.ZodOptional<z.ZodNullable<z.ZodString>>;
130
+ delta: z.ZodObject<{
131
+ role: z.ZodOptional<z.ZodString>;
132
+ content: z.ZodOptional<z.ZodString>;
133
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
134
+ role: z.ZodOptional<z.ZodString>;
135
+ content: z.ZodOptional<z.ZodString>;
136
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
137
+ role: z.ZodOptional<z.ZodString>;
138
+ content: z.ZodOptional<z.ZodString>;
139
+ }, z.ZodTypeAny, "passthrough">>;
140
+ }, "strip", z.ZodTypeAny, {
141
+ index: number;
142
+ delta: {
143
+ content?: string | undefined;
144
+ role?: string | undefined;
145
+ } & {
146
+ [k: string]: unknown;
147
+ };
148
+ finish_reason?: string | null | undefined;
149
+ }, {
150
+ index: number;
151
+ delta: {
152
+ content?: string | undefined;
153
+ role?: string | undefined;
154
+ } & {
155
+ [k: string]: unknown;
156
+ };
157
+ finish_reason?: string | null | undefined;
158
+ }>, "many">;
159
+ timings: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNumber>>;
160
+ }, "strip", z.ZodTypeAny, {
161
+ object: string;
162
+ id: string;
163
+ choices: {
164
+ index: number;
165
+ delta: {
166
+ content?: string | undefined;
167
+ role?: string | undefined;
168
+ } & {
169
+ [k: string]: unknown;
170
+ };
171
+ finish_reason?: string | null | undefined;
172
+ }[];
173
+ model: string;
174
+ created: number;
175
+ system_fingerprint?: string | undefined;
176
+ timings?: Record<string, number> | undefined;
177
+ }, {
178
+ object: string;
179
+ id: string;
180
+ choices: {
181
+ index: number;
182
+ delta: {
183
+ content?: string | undefined;
184
+ role?: string | undefined;
185
+ } & {
186
+ [k: string]: unknown;
187
+ };
188
+ finish_reason?: string | null | undefined;
189
+ }[];
190
+ model: string;
191
+ created: number;
192
+ system_fingerprint?: string | undefined;
193
+ timings?: Record<string, number> | undefined;
194
+ }>]>>;
195
+ id: z.ZodOptional<z.ZodString>;
196
+ event: z.ZodOptional<z.ZodString>;
197
+ retry: z.ZodOptional<z.ZodNumber>;
198
+ }, "strip", z.ZodTypeAny, {
199
+ data: {
200
+ object: string;
201
+ id: string;
202
+ choices: {
203
+ index: number;
204
+ delta: {
205
+ content?: string | undefined;
206
+ role?: string | undefined;
207
+ } & {
208
+ [k: string]: unknown;
209
+ };
210
+ finish_reason?: string | null | undefined;
211
+ }[];
212
+ model: string;
213
+ created: number;
214
+ system_fingerprint?: string | undefined;
215
+ timings?: Record<string, number> | undefined;
216
+ } | {
217
+ isDone: true;
218
+ };
219
+ id?: string | undefined;
220
+ event?: string | undefined;
221
+ retry?: number | undefined;
222
+ }, {
223
+ data: string;
224
+ id?: string | undefined;
225
+ event?: string | undefined;
226
+ retry?: number | undefined;
227
+ }>;
@@ -1,2 +1,42 @@
1
- export {};
1
+ import z from "zod";
2
+ export const LLMResponseSchema = z.object({
3
+ id: z.string(),
4
+ object: z.string(),
5
+ created: z.number(),
6
+ model: z.string(),
7
+ system_fingerprint: z.string().optional(),
8
+ choices: z.array(z.object({
9
+ index: z.number(),
10
+ finish_reason: z.string().nullable().optional(),
11
+ delta: z
12
+ .object({
13
+ role: z.string().optional(),
14
+ content: z.string().optional(),
15
+ })
16
+ .passthrough(),
17
+ })),
18
+ timings: z.record(z.number()).optional(),
19
+ });
20
+ export const SSEMessageSchema = z.object({
21
+ data: z
22
+ .string()
23
+ .transform((str, ctx) => {
24
+ if (str === "[DONE]")
25
+ return { isDone: true };
26
+ try {
27
+ return JSON.parse(str);
28
+ }
29
+ catch {
30
+ ctx.addIssue({
31
+ code: z.ZodIssueCode.custom,
32
+ message: "Invalid JSON string",
33
+ });
34
+ return z.NEVER;
35
+ }
36
+ })
37
+ .pipe(z.union([z.object({ isDone: z.literal(true) }), LLMResponseSchema])),
38
+ id: z.string().optional(),
39
+ event: z.string().optional(),
40
+ retry: z.number().optional(),
41
+ });
2
42
  //# sourceMappingURL=types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/cli/hooks/useLlmStream/types.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/cli/hooks/useLlmStream/types.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,KAAK,CAAC;AA2BpB,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;IACd,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACzC,OAAO,EAAE,CAAC,CAAC,KAAK,CACf,CAAC,CAAC,MAAM,CAAC;QACR,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;QACjB,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;QAC/C,KAAK,EAAE,CAAC;aACN,MAAM,CAAC;YACP,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;YAC3B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;SAC9B,CAAC;aACD,WAAW,EAAE;KACf,CAAC,CACF;IACD,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;CACxC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,IAAI,EAAE,CAAC;SACL,MAAM,EAAE;SACR,SAAS,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QACvB,IAAI,GAAG,KAAK,QAAQ;YAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QAE9C,IAAI,CAAC;YACJ,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACxB,CAAC;QAAC,MAAM,CAAC;YACR,GAAG,CAAC,QAAQ,CAAC;gBACZ,IAAI,EAAE,CAAC,CAAC,YAAY,CAAC,MAAM;gBAC3B,OAAO,EAAE,qBAAqB;aAC9B,CAAC,CAAC;YACH,OAAO,CAAC,CAAC,KAAK,CAAC;QAChB,CAAC;IACF,CAAC,CAAC;SACD,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAC3E,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACzB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC5B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC5B,CAAC,CAAC"}
@@ -1,12 +1,24 @@
1
1
  import type { McpToolInfo } from "../../services/McpClientService.js";
2
2
  import type { CallToolFn, PendingItem, StreamingState } from "../../types.js";
3
+ import type { useHistoryManager } from "../useHistoryManager.js";
3
4
  export interface LlmStreamState {
4
5
  pendingItem: PendingItem | null;
5
6
  streamingState: StreamingState;
6
7
  isLoading: boolean;
7
8
  error: Error | null;
9
+ lastOutputTime: number;
8
10
  sendMessage: (text: string, ragContext?: string | null, overrideTools?: McpToolInfo[]) => Promise<void>;
11
+ submitQuery: (query: string, options?: {
12
+ overrideTools?: McpToolInfo[];
13
+ ragContext?: string | null;
14
+ timestamp?: number;
15
+ }) => Promise<void>;
9
16
  abortCurrentStream: () => void;
10
17
  clearStreamingHistory: () => void;
11
18
  }
12
- export declare const useLlmStream: (callTool?: CallToolFn, availableTools?: McpToolInfo[]) => LlmStreamState;
19
+ export interface LLMStreamOptions {
20
+ addItem: ReturnType<typeof useHistoryManager>["addItem"];
21
+ callTool?: CallToolFn;
22
+ availableTools: McpToolInfo[];
23
+ }
24
+ export declare const useLlmStream: ({ addItem, callTool, availableTools, }: LLMStreamOptions) => LlmStreamState;