skyloom 1.14.6 → 1.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/.github/workflows/ci.yml +2 -2
  2. package/.github/workflows/publish.yml +74 -0
  3. package/CONVERSION_PLAN.md +191 -191
  4. package/README.md +523 -220
  5. package/config/default.yaml +46 -43
  6. package/config/models.yaml +928 -155
  7. package/config/providers.yaml +109 -6
  8. package/dist/agents/snow.d.ts +2 -0
  9. package/dist/agents/snow.d.ts.map +1 -1
  10. package/dist/agents/snow.js +36 -5
  11. package/dist/agents/snow.js.map +1 -1
  12. package/dist/cli/loom_chat.d.ts.map +1 -1
  13. package/dist/cli/loom_chat.js +207 -1
  14. package/dist/cli/loom_chat.js.map +1 -1
  15. package/dist/cli/main.js +190 -40
  16. package/dist/cli/main.js.map +1 -1
  17. package/dist/cli/tui.d.ts.map +1 -1
  18. package/dist/cli/tui.js +6 -31
  19. package/dist/cli/tui.js.map +1 -1
  20. package/dist/core/agent.d.ts +6 -4
  21. package/dist/core/agent.d.ts.map +1 -1
  22. package/dist/core/agent.js +61 -20
  23. package/dist/core/agent.js.map +1 -1
  24. package/dist/core/catalog.d.ts.map +1 -1
  25. package/dist/core/catalog.js +30 -9
  26. package/dist/core/catalog.js.map +1 -1
  27. package/dist/core/commands.d.ts +110 -0
  28. package/dist/core/commands.d.ts.map +1 -0
  29. package/dist/core/commands.js +633 -0
  30. package/dist/core/commands.js.map +1 -0
  31. package/dist/core/concurrency.d.ts +38 -0
  32. package/dist/core/concurrency.d.ts.map +1 -0
  33. package/dist/core/concurrency.js +65 -0
  34. package/dist/core/concurrency.js.map +1 -0
  35. package/dist/core/factory.js +16 -16
  36. package/dist/core/file_checkpoint.d.ts +9 -0
  37. package/dist/core/file_checkpoint.d.ts.map +1 -1
  38. package/dist/core/file_checkpoint.js +33 -1
  39. package/dist/core/file_checkpoint.js.map +1 -1
  40. package/dist/core/llm.d.ts.map +1 -1
  41. package/dist/core/llm.js +66 -13
  42. package/dist/core/llm.js.map +1 -1
  43. package/dist/core/memory.js +51 -51
  44. package/dist/core/schemas.d.ts +16 -0
  45. package/dist/core/schemas.d.ts.map +1 -1
  46. package/dist/core/schemas.js +32 -0
  47. package/dist/core/schemas.js.map +1 -1
  48. package/dist/core/security.d.ts.map +1 -1
  49. package/dist/core/security.js +27 -0
  50. package/dist/core/security.js.map +1 -1
  51. package/dist/core/skymd.js +14 -14
  52. package/dist/core/trace.d.ts +105 -0
  53. package/dist/core/trace.d.ts.map +1 -0
  54. package/dist/core/trace.js +213 -0
  55. package/dist/core/trace.js.map +1 -0
  56. package/dist/tools/builtin.d.ts +2 -6
  57. package/dist/tools/builtin.d.ts.map +1 -1
  58. package/dist/tools/builtin.js +180 -125
  59. package/dist/tools/builtin.js.map +1 -1
  60. package/dist/tools/extra.d.ts +13 -0
  61. package/dist/tools/extra.d.ts.map +1 -0
  62. package/dist/tools/extra.js +827 -0
  63. package/dist/tools/extra.js.map +1 -0
  64. package/dist/tools/guards.d.ts +12 -0
  65. package/dist/tools/guards.d.ts.map +1 -0
  66. package/dist/tools/guards.js +143 -0
  67. package/dist/tools/guards.js.map +1 -0
  68. package/dist/tools/model_tool.d.ts.map +1 -1
  69. package/dist/tools/model_tool.js +24 -4
  70. package/dist/tools/model_tool.js.map +1 -1
  71. package/dist/web/markdown.d.ts +32 -0
  72. package/dist/web/markdown.d.ts.map +1 -0
  73. package/dist/web/markdown.js +202 -0
  74. package/dist/web/markdown.js.map +1 -0
  75. package/dist/web/server.d.ts +4 -0
  76. package/dist/web/server.d.ts.map +1 -1
  77. package/dist/web/server.js +14 -582
  78. package/dist/web/server.js.map +1 -1
  79. package/dist/web/ui.d.ts +31 -0
  80. package/dist/web/ui.d.ts.map +1 -0
  81. package/dist/web/ui.js +1009 -0
  82. package/dist/web/ui.js.map +1 -0
  83. package/docs/AESTHETIC_DESIGN.md +152 -152
  84. package/docs/OPTIMIZATION_PLAN.md +178 -178
  85. package/package.json +68 -68
  86. package/src/agents/snow.ts +38 -5
  87. package/src/cli/commands_md.ts +112 -112
  88. package/src/cli/input_macros.ts +83 -83
  89. package/src/cli/loom.ts +1041 -1041
  90. package/src/cli/loom_chat.ts +772 -603
  91. package/src/cli/main.ts +853 -723
  92. package/src/cli/tui.ts +264 -289
  93. package/src/core/agent/guard.ts +133 -133
  94. package/src/core/agent/task.ts +100 -100
  95. package/src/core/agent.ts +1630 -1590
  96. package/src/core/agent_helpers.ts +500 -500
  97. package/src/core/bus.ts +221 -221
  98. package/src/core/cache.ts +153 -153
  99. package/src/core/catalog.ts +199 -178
  100. package/src/core/circuit_breaker.ts +119 -119
  101. package/src/core/commands.ts +704 -0
  102. package/src/core/concurrency.ts +73 -0
  103. package/src/core/config.ts +365 -365
  104. package/src/core/constants.ts +95 -95
  105. package/src/core/factory.ts +656 -656
  106. package/src/core/file_checkpoint.ts +163 -136
  107. package/src/core/hooks.ts +126 -126
  108. package/src/core/llm.ts +972 -915
  109. package/src/core/logger.ts +143 -143
  110. package/src/core/mcp.ts +1001 -1001
  111. package/src/core/memory.ts +1201 -1201
  112. package/src/core/middleware.ts +350 -350
  113. package/src/core/model_config.ts +159 -159
  114. package/src/core/pipelines.ts +424 -424
  115. package/src/core/schemas.ts +319 -282
  116. package/src/core/security.ts +27 -0
  117. package/src/core/semantic.ts +211 -211
  118. package/src/core/skill.ts +384 -384
  119. package/src/core/skymd.ts +143 -143
  120. package/src/core/theme.ts +65 -65
  121. package/src/core/tool.ts +457 -457
  122. package/src/core/trace.ts +236 -0
  123. package/src/core/verify.ts +71 -71
  124. package/src/plugins/loader.ts +91 -91
  125. package/src/skills/loader.ts +75 -75
  126. package/src/tools/builtin.ts +571 -493
  127. package/src/tools/computer.ts +279 -279
  128. package/src/tools/extra.ts +662 -0
  129. package/src/tools/guards.ts +82 -0
  130. package/src/tools/model_tool.ts +93 -74
  131. package/src/tools/todo.ts +76 -76
  132. package/src/web/markdown.ts +193 -0
  133. package/src/web/server.ts +117 -693
  134. package/src/web/ui.ts +949 -0
  135. package/tests/agent.test.ts +211 -159
  136. package/tests/agent_helpers.test.ts +48 -48
  137. package/tests/catalog.test.ts +86 -86
  138. package/tests/checkpoint_commands.test.ts +124 -124
  139. package/tests/claude_compat.test.ts +110 -110
  140. package/tests/commands.test.ts +103 -0
  141. package/tests/concurrency.test.ts +102 -0
  142. package/tests/config.test.ts +41 -41
  143. package/tests/extra_tools.test.ts +212 -0
  144. package/tests/fence_plugin.test.ts +52 -52
  145. package/tests/guard.test.ts +75 -75
  146. package/tests/loom.test.ts +337 -337
  147. package/tests/memory.test.ts +170 -170
  148. package/tests/model_config.test.ts +109 -109
  149. package/tests/skymd.test.ts +146 -146
  150. package/tests/ssrf.test.ts +38 -38
  151. package/tests/structured_retry.test.ts +87 -0
  152. package/tests/task.test.ts +60 -60
  153. package/tests/todo_toolstats.test.ts +94 -94
  154. package/tests/trace.test.ts +128 -0
  155. package/tests/tui.test.ts +67 -67
  156. package/tests/web.test.ts +169 -0
  157. package/tsconfig.json +38 -38
package/src/core/cache.ts CHANGED
@@ -1,153 +1,153 @@
1
- /**
2
- * Lightweight LRU cache for LLM responses.
3
- *
4
- * Deduplicates identical requests within a configurable time window.
5
- * Keyed by (model, messages_json) hash.
6
- */
7
-
8
- import crypto from 'crypto';
9
-
10
- /**
11
- * Cache entry containing timestamp and response.
12
- */
13
- interface CacheEntry {
14
- timestamp: number;
15
- response: string;
16
- }
17
-
18
- /**
19
- * LRU cache for LLM completions with TTL expiration.
20
- */
21
- export class LLMCache {
22
- private maxSize: number;
23
- private ttlSeconds: number;
24
- private cache: Map<string, CacheEntry> = new Map();
25
-
26
- constructor(maxSize: number = 128, ttlSeconds: number = 60) {
27
- this.maxSize = maxSize;
28
- this.ttlSeconds = ttlSeconds;
29
- }
30
-
31
- /**
32
- * Generate a cache key from model, messages, and parameters.
33
- *
34
- * Uses SHA256 hash for deterministic, compact keys. Parameters are sorted
35
- * to ensure consistent keys regardless of key order.
36
- */
37
- private makeKey(
38
- model: string,
39
- messages: Record<string, any>[],
40
- params?: Record<string, any>
41
- ): string {
42
- const raw = JSON.stringify([model, messages, params || {}], this.jsonReplacer);
43
- return crypto.createHash('sha256').update(raw).digest('hex').slice(0, 32);
44
- }
45
-
46
- /**
47
- * JSON replacer for consistent serialization.
48
- */
49
- private jsonReplacer(_key: string, value: any): any {
50
- if (typeof value === 'function') {
51
- return undefined;
52
- }
53
- return value;
54
- }
55
-
56
- /**
57
- * Get a cached response if it exists and hasn't expired.
58
- *
59
- * @param model - LLM model name
60
- * @param messages - Conversation messages
61
- * @param params - Optional parameters
62
- * @returns Cached response or null if miss/expired
63
- */
64
- get(
65
- model: string,
66
- messages: Record<string, any>[],
67
- params?: Record<string, any>
68
- ): string | null {
69
- const key = this.makeKey(model, messages, params);
70
- const entry = this.cache.get(key);
71
-
72
- if (!entry) {
73
- return null;
74
- }
75
-
76
- // Check if expired
77
- const now = Date.now();
78
- const ageSeconds = (now - entry.timestamp) / 1000;
79
-
80
- if (ageSeconds >= this.ttlSeconds) {
81
- this.cache.delete(key);
82
- return null;
83
- }
84
-
85
- // Move to end (LRU)
86
- this.cache.delete(key);
87
- this.cache.set(key, entry);
88
-
89
- return entry.response;
90
- }
91
-
92
- /**
93
- * Cache a response.
94
- *
95
- * Refuses to cache empty or very short content to avoid bloat.
96
- * Also performs LRU eviction if cache exceeds max_size.
97
- *
98
- * @param model - LLM model name
99
- * @param messages - Conversation messages
100
- * @param response - LLM response to cache
101
- * @param params - Optional parameters
102
- */
103
- set(
104
- model: string,
105
- messages: Record<string, any>[],
106
- response: string,
107
- params?: Record<string, any>
108
- ): void {
109
- // Don't cache empty or very short responses
110
- if (!response || response.length < 10) {
111
- return;
112
- }
113
-
114
- const key = this.makeKey(model, messages, params);
115
- const entry: CacheEntry = {
116
- timestamp: Date.now(),
117
- response,
118
- };
119
-
120
- this.cache.delete(key);
121
- this.cache.set(key, entry);
122
-
123
- // Evict oldest entries if over capacity
124
- while (this.cache.size > this.maxSize) {
125
- const firstKey = this.cache.keys().next().value;
126
- if (firstKey !== undefined) this.cache.delete(firstKey);
127
- }
128
- }
129
-
130
- /**
131
- * Clear all cache entries.
132
- */
133
- clear(): void {
134
- this.cache.clear();
135
- }
136
-
137
- /**
138
- * Get current cache size.
139
- */
140
- get size(): number {
141
- return this.cache.size;
142
- }
143
-
144
- /**
145
- * Get cache hit rate statistics.
146
- */
147
- getStats(): { size: number; maxSize: number } {
148
- return {
149
- size: this.cache.size,
150
- maxSize: this.maxSize,
151
- };
152
- }
153
- }
1
+ /**
2
+ * Lightweight LRU cache for LLM responses.
3
+ *
4
+ * Deduplicates identical requests within a configurable time window.
5
+ * Keyed by (model, messages_json) hash.
6
+ */
7
+
8
+ import crypto from 'crypto';
9
+
10
+ /**
11
+ * Cache entry containing timestamp and response.
12
+ */
13
+ interface CacheEntry {
14
+ timestamp: number;
15
+ response: string;
16
+ }
17
+
18
+ /**
19
+ * LRU cache for LLM completions with TTL expiration.
20
+ */
21
+ export class LLMCache {
22
+ private maxSize: number;
23
+ private ttlSeconds: number;
24
+ private cache: Map<string, CacheEntry> = new Map();
25
+
26
+ constructor(maxSize: number = 128, ttlSeconds: number = 60) {
27
+ this.maxSize = maxSize;
28
+ this.ttlSeconds = ttlSeconds;
29
+ }
30
+
31
+ /**
32
+ * Generate a cache key from model, messages, and parameters.
33
+ *
34
+ * Uses SHA256 hash for deterministic, compact keys. Parameters are sorted
35
+ * to ensure consistent keys regardless of key order.
36
+ */
37
+ private makeKey(
38
+ model: string,
39
+ messages: Record<string, any>[],
40
+ params?: Record<string, any>
41
+ ): string {
42
+ const raw = JSON.stringify([model, messages, params || {}], this.jsonReplacer);
43
+ return crypto.createHash('sha256').update(raw).digest('hex').slice(0, 32);
44
+ }
45
+
46
+ /**
47
+ * JSON replacer for consistent serialization.
48
+ */
49
+ private jsonReplacer(_key: string, value: any): any {
50
+ if (typeof value === 'function') {
51
+ return undefined;
52
+ }
53
+ return value;
54
+ }
55
+
56
+ /**
57
+ * Get a cached response if it exists and hasn't expired.
58
+ *
59
+ * @param model - LLM model name
60
+ * @param messages - Conversation messages
61
+ * @param params - Optional parameters
62
+ * @returns Cached response or null if miss/expired
63
+ */
64
+ get(
65
+ model: string,
66
+ messages: Record<string, any>[],
67
+ params?: Record<string, any>
68
+ ): string | null {
69
+ const key = this.makeKey(model, messages, params);
70
+ const entry = this.cache.get(key);
71
+
72
+ if (!entry) {
73
+ return null;
74
+ }
75
+
76
+ // Check if expired
77
+ const now = Date.now();
78
+ const ageSeconds = (now - entry.timestamp) / 1000;
79
+
80
+ if (ageSeconds >= this.ttlSeconds) {
81
+ this.cache.delete(key);
82
+ return null;
83
+ }
84
+
85
+ // Move to end (LRU)
86
+ this.cache.delete(key);
87
+ this.cache.set(key, entry);
88
+
89
+ return entry.response;
90
+ }
91
+
92
+ /**
93
+ * Cache a response.
94
+ *
95
+ * Refuses to cache empty or very short content to avoid bloat.
96
+ * Also performs LRU eviction if cache exceeds max_size.
97
+ *
98
+ * @param model - LLM model name
99
+ * @param messages - Conversation messages
100
+ * @param response - LLM response to cache
101
+ * @param params - Optional parameters
102
+ */
103
+ set(
104
+ model: string,
105
+ messages: Record<string, any>[],
106
+ response: string,
107
+ params?: Record<string, any>
108
+ ): void {
109
+ // Don't cache empty or very short responses
110
+ if (!response || response.length < 10) {
111
+ return;
112
+ }
113
+
114
+ const key = this.makeKey(model, messages, params);
115
+ const entry: CacheEntry = {
116
+ timestamp: Date.now(),
117
+ response,
118
+ };
119
+
120
+ this.cache.delete(key);
121
+ this.cache.set(key, entry);
122
+
123
+ // Evict oldest entries if over capacity
124
+ while (this.cache.size > this.maxSize) {
125
+ const firstKey = this.cache.keys().next().value;
126
+ if (firstKey !== undefined) this.cache.delete(firstKey);
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Clear all cache entries.
132
+ */
133
+ clear(): void {
134
+ this.cache.clear();
135
+ }
136
+
137
+ /**
138
+ * Get current cache size.
139
+ */
140
+ get size(): number {
141
+ return this.cache.size;
142
+ }
143
+
144
+ /**
145
+ * Get cache hit rate statistics.
146
+ */
147
+ getStats(): { size: number; maxSize: number } {
148
+ return {
149
+ size: this.cache.size,
150
+ maxSize: this.maxSize,
151
+ };
152
+ }
153
+ }