@smooai/smooth-operator-core 1.8.0 → 1.8.1
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/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/promptCache.d.ts +64 -0
- package/dist/promptCache.d.ts.map +1 -0
- package/dist/promptCache.js +101 -0
- package/dist/promptCache.js.map +1 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -30,6 +30,7 @@ export type { Knowledge, KnowledgeHit } from './knowledge.js';
|
|
|
30
30
|
export { MockLlmProvider, SCRIPTED_USAGE, textResponse, toolCallResponse } from './llmProvider.js';
|
|
31
31
|
export type { LlmProvider, RecordedCall, ScriptedMessage, ScriptedUsage } from './llmProvider.js';
|
|
32
32
|
export { InMemoryMemory } from './memory.js';
|
|
33
|
+
export { PROMPT_CACHE_BOUNDARY, PromptCache } from './promptCache.js';
|
|
33
34
|
export type { Memory, MemoryEntry } from './memory.js';
|
|
34
35
|
export { hasInjection, hasSecrets, NarcHook, redactMatch, scanInjection, scanSecrets, Severity, severityLabel } from './narc.js';
|
|
35
36
|
export type { NarcAlert, NarcFinding } from './narc.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -18,6 +18,7 @@ export { DenyPolicy, DenyRules, globMatch } from './denyPolicy.js';
|
|
|
18
18
|
export { InMemoryKnowledge } from './knowledge.js';
|
|
19
19
|
export { MockLlmProvider, SCRIPTED_USAGE, textResponse, toolCallResponse } from './llmProvider.js';
|
|
20
20
|
export { InMemoryMemory } from './memory.js';
|
|
21
|
+
export { PROMPT_CACHE_BOUNDARY, PromptCache } from './promptCache.js';
|
|
21
22
|
export { hasInjection, hasSecrets, NarcHook, redactMatch, scanInjection, scanSecrets, Severity, severityLabel } from './narc.js';
|
|
22
23
|
export { LexicalReranker, NoopReranker } from './rerank.js';
|
|
23
24
|
export { SmoothAgentThread } from './thread.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE3E,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAEhE,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAE1D,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,eAAe,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE/I,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAEjG,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5E,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEzF,OAAO,EACH,QAAQ,EACR,eAAe,EACf,iBAAiB,EACjB,MAAM,EACN,uBAAuB,EACvB,YAAY,EACZ,aAAa,EACb,cAAc,EACd,aAAa,EACb,oBAAoB,EACpB,YAAY,GACf,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE1E,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEnD,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEnG,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE3E,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAEhE,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAE1D,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,eAAe,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE/I,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAEjG,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5E,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEzF,OAAO,EACH,QAAQ,EACR,eAAe,EACf,iBAAiB,EACjB,MAAM,EACN,uBAAuB,EACvB,YAAY,EACZ,aAAa,EACb,cAAc,EACd,aAAa,EACb,oBAAoB,EACpB,YAAY,GACf,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE1E,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEnD,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEnG,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEtE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAEjI,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEvE,OAAO,EAAE,GAAG,EAAE,eAAe,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt caching — the static/dynamic system-prompt split. The TypeScript port
|
|
3
|
+
* of the Rust reference `smooth-operator-core::conversation::PromptCache`.
|
|
4
|
+
*
|
|
5
|
+
* A system prompt has two halves with very different churn rates: role
|
|
6
|
+
* instructions and tool schemas barely change, while project context
|
|
7
|
+
* (AGENTS.md / CLAUDE.md, the working set) changes every turn. Anthropic's
|
|
8
|
+
* prompt cache keys on a PREFIX, so putting the volatile half first invalidates
|
|
9
|
+
* the whole thing. {@link PROMPT_CACHE_BOUNDARY} splits them: everything above
|
|
10
|
+
* the marker is static and hashed once for cache-key dedup, everything below is
|
|
11
|
+
* dynamic and can be swapped without busting the static prefix.
|
|
12
|
+
*
|
|
13
|
+
* Feed the result to the agent as its instructions:
|
|
14
|
+
*
|
|
15
|
+
* ```ts
|
|
16
|
+
* const cache = new PromptCache(`${rules}${PROMPT_CACHE_BOUNDARY}${projectContext}`);
|
|
17
|
+
* new SmoothAgent(provider, { instructions: cache.fullPrompt() });
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Marker that splits a system prompt into a cacheable static portion and a
|
|
22
|
+
* frequently-changing dynamic portion.
|
|
23
|
+
*/
|
|
24
|
+
export declare const PROMPT_CACHE_BOUNDARY = "__PROMPT_CACHE_BOUNDARY__";
|
|
25
|
+
/** A system prompt split at {@link PROMPT_CACHE_BOUNDARY}. */
|
|
26
|
+
export declare class PromptCache {
|
|
27
|
+
/** The cacheable half (above the marker). */
|
|
28
|
+
readonly staticPortion: string;
|
|
29
|
+
/** The frequently-changing half (below the marker). */
|
|
30
|
+
dynamicPortion: string;
|
|
31
|
+
private readonly _staticHash;
|
|
32
|
+
private readonly _staticTokens;
|
|
33
|
+
/**
|
|
34
|
+
* Split a system prompt at the boundary marker. With no marker the entire
|
|
35
|
+
* prompt is treated as dynamic — nothing is claimed cacheable that the
|
|
36
|
+
* caller didn't mark.
|
|
37
|
+
*/
|
|
38
|
+
constructor(prompt: string);
|
|
39
|
+
/**
|
|
40
|
+
* Reassemble static + boundary + dynamic. With no static portion the dynamic
|
|
41
|
+
* half is returned alone, so a prompt that was never split round-trips
|
|
42
|
+
* unchanged rather than gaining a stray marker.
|
|
43
|
+
*/
|
|
44
|
+
fullPrompt(): string;
|
|
45
|
+
/**
|
|
46
|
+
* Swap the dynamic half, leaving the static half and its hash untouched —
|
|
47
|
+
* the whole point of the split.
|
|
48
|
+
*/
|
|
49
|
+
updateDynamic(dynamic: string): void;
|
|
50
|
+
/**
|
|
51
|
+
* Identifies the static portion for cache-key deduplication.
|
|
52
|
+
*
|
|
53
|
+
* Process-local only: it is compared against other hashes from THIS engine,
|
|
54
|
+
* never sent on the wire, so it deliberately does not match the Rust
|
|
55
|
+
* reference's value (Rust uses `DefaultHasher`, which is not reproducible
|
|
56
|
+
* across languages — or even across Rust releases). The ported contract is
|
|
57
|
+
* the behavior: same static text hashes the same, different static text
|
|
58
|
+
* hashes differently, and `updateDynamic` never changes it.
|
|
59
|
+
*/
|
|
60
|
+
staticHash(): string;
|
|
61
|
+
/** Estimated tokens the static portion saves on a cache hit. */
|
|
62
|
+
cachedTokens(): number;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=promptCache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"promptCache.d.ts","sourceRoot":"","sources":["../src/promptCache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH;;;GAGG;AACH,eAAO,MAAM,qBAAqB,8BAA8B,CAAC;AAEjE,8DAA8D;AAC9D,qBAAa,WAAW;IACpB,6CAA6C;IAC7C,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,uDAAuD;IACvD,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IAEvC;;;;OAIG;gBACS,MAAM,EAAE,MAAM;IAa1B;;;;OAIG;IACH,UAAU,IAAI,MAAM;IAKpB;;;OAGG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAIpC;;;;;;;;;OASG;IACH,UAAU,IAAI,MAAM;IAIpB,gEAAgE;IAChE,YAAY,IAAI,MAAM;CAGzB"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt caching — the static/dynamic system-prompt split. The TypeScript port
|
|
3
|
+
* of the Rust reference `smooth-operator-core::conversation::PromptCache`.
|
|
4
|
+
*
|
|
5
|
+
* A system prompt has two halves with very different churn rates: role
|
|
6
|
+
* instructions and tool schemas barely change, while project context
|
|
7
|
+
* (AGENTS.md / CLAUDE.md, the working set) changes every turn. Anthropic's
|
|
8
|
+
* prompt cache keys on a PREFIX, so putting the volatile half first invalidates
|
|
9
|
+
* the whole thing. {@link PROMPT_CACHE_BOUNDARY} splits them: everything above
|
|
10
|
+
* the marker is static and hashed once for cache-key dedup, everything below is
|
|
11
|
+
* dynamic and can be swapped without busting the static prefix.
|
|
12
|
+
*
|
|
13
|
+
* Feed the result to the agent as its instructions:
|
|
14
|
+
*
|
|
15
|
+
* ```ts
|
|
16
|
+
* const cache = new PromptCache(`${rules}${PROMPT_CACHE_BOUNDARY}${projectContext}`);
|
|
17
|
+
* new SmoothAgent(provider, { instructions: cache.fullPrompt() });
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Marker that splits a system prompt into a cacheable static portion and a
|
|
22
|
+
* frequently-changing dynamic portion.
|
|
23
|
+
*/
|
|
24
|
+
export const PROMPT_CACHE_BOUNDARY = '__PROMPT_CACHE_BOUNDARY__';
|
|
25
|
+
/** A system prompt split at {@link PROMPT_CACHE_BOUNDARY}. */
|
|
26
|
+
export class PromptCache {
|
|
27
|
+
/** The cacheable half (above the marker). */
|
|
28
|
+
staticPortion;
|
|
29
|
+
/** The frequently-changing half (below the marker). */
|
|
30
|
+
dynamicPortion;
|
|
31
|
+
_staticHash;
|
|
32
|
+
_staticTokens;
|
|
33
|
+
/**
|
|
34
|
+
* Split a system prompt at the boundary marker. With no marker the entire
|
|
35
|
+
* prompt is treated as dynamic — nothing is claimed cacheable that the
|
|
36
|
+
* caller didn't mark.
|
|
37
|
+
*/
|
|
38
|
+
constructor(prompt) {
|
|
39
|
+
const idx = prompt.indexOf(PROMPT_CACHE_BOUNDARY);
|
|
40
|
+
if (idx < 0) {
|
|
41
|
+
this.staticPortion = '';
|
|
42
|
+
this.dynamicPortion = prompt;
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
this.staticPortion = prompt.slice(0, idx);
|
|
46
|
+
this.dynamicPortion = prompt.slice(idx + PROMPT_CACHE_BOUNDARY.length);
|
|
47
|
+
}
|
|
48
|
+
this._staticHash = hashPromptPortion(this.staticPortion);
|
|
49
|
+
this._staticTokens = this.staticPortion === '' ? 0 : Math.floor(this.staticPortion.length / 4) + 1;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Reassemble static + boundary + dynamic. With no static portion the dynamic
|
|
53
|
+
* half is returned alone, so a prompt that was never split round-trips
|
|
54
|
+
* unchanged rather than gaining a stray marker.
|
|
55
|
+
*/
|
|
56
|
+
fullPrompt() {
|
|
57
|
+
if (this.staticPortion === '')
|
|
58
|
+
return this.dynamicPortion;
|
|
59
|
+
return `${this.staticPortion}${PROMPT_CACHE_BOUNDARY}${this.dynamicPortion}`;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Swap the dynamic half, leaving the static half and its hash untouched —
|
|
63
|
+
* the whole point of the split.
|
|
64
|
+
*/
|
|
65
|
+
updateDynamic(dynamic) {
|
|
66
|
+
this.dynamicPortion = dynamic;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Identifies the static portion for cache-key deduplication.
|
|
70
|
+
*
|
|
71
|
+
* Process-local only: it is compared against other hashes from THIS engine,
|
|
72
|
+
* never sent on the wire, so it deliberately does not match the Rust
|
|
73
|
+
* reference's value (Rust uses `DefaultHasher`, which is not reproducible
|
|
74
|
+
* across languages — or even across Rust releases). The ported contract is
|
|
75
|
+
* the behavior: same static text hashes the same, different static text
|
|
76
|
+
* hashes differently, and `updateDynamic` never changes it.
|
|
77
|
+
*/
|
|
78
|
+
staticHash() {
|
|
79
|
+
return this._staticHash;
|
|
80
|
+
}
|
|
81
|
+
/** Estimated tokens the static portion saves on a cache hit. */
|
|
82
|
+
cachedTokens() {
|
|
83
|
+
return this._staticTokens;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* FNV-1a (64-bit), the same non-cryptographic hash family the vector embedder
|
|
88
|
+
* uses, rendered as 16 hex chars like the Rust reference. BigInt because a
|
|
89
|
+
* 64-bit multiply overflows a JS number.
|
|
90
|
+
*/
|
|
91
|
+
function hashPromptPortion(s) {
|
|
92
|
+
const MASK = (1n << 64n) - 1n;
|
|
93
|
+
let h = 14695981039346656037n;
|
|
94
|
+
const bytes = new TextEncoder().encode(s);
|
|
95
|
+
for (const b of bytes) {
|
|
96
|
+
h = (h ^ BigInt(b)) & MASK;
|
|
97
|
+
h = (h * 1099511628211n) & MASK;
|
|
98
|
+
}
|
|
99
|
+
return h.toString(16).padStart(16, '0');
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=promptCache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"promptCache.js","sourceRoot":"","sources":["../src/promptCache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,2BAA2B,CAAC;AAEjE,8DAA8D;AAC9D,MAAM,OAAO,WAAW;IACpB,6CAA6C;IACpC,aAAa,CAAS;IAC/B,uDAAuD;IACvD,cAAc,CAAS;IACN,WAAW,CAAS;IACpB,aAAa,CAAS;IAEvC;;;;OAIG;IACH,YAAY,MAAc;QACtB,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC;QAClD,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;YACV,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC;YACxB,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC;QACjC,CAAC;aAAM,CAAC;YACJ,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YAC1C,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC;QAC3E,CAAC;QACD,IAAI,CAAC,WAAW,GAAG,iBAAiB,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACzD,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;IACvG,CAAC;IAED;;;;OAIG;IACH,UAAU;QACN,IAAI,IAAI,CAAC,aAAa,KAAK,EAAE;YAAE,OAAO,IAAI,CAAC,cAAc,CAAC;QAC1D,OAAO,GAAG,IAAI,CAAC,aAAa,GAAG,qBAAqB,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;IACjF,CAAC;IAED;;;OAGG;IACH,aAAa,CAAC,OAAe;QACzB,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC;IAClC,CAAC;IAED;;;;;;;;;OASG;IACH,UAAU;QACN,OAAO,IAAI,CAAC,WAAW,CAAC;IAC5B,CAAC;IAED,gEAAgE;IAChE,YAAY;QACR,OAAO,IAAI,CAAC,aAAa,CAAC;IAC9B,CAAC;CACJ;AAED;;;;GAIG;AACH,SAAS,iBAAiB,CAAC,CAAS;IAChC,MAAM,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,GAAG,EAAE,CAAC;IAC9B,IAAI,CAAC,GAAG,qBAAqB,CAAC;IAC9B,MAAM,KAAK,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAC1C,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACpB,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;QAC3B,CAAC,GAAG,CAAC,CAAC,GAAG,cAAc,CAAC,GAAG,IAAI,CAAC;IACpC,CAAC;IACD,OAAO,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;AAC5C,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smooai/smooth-operator-core",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.1",
|
|
4
4
|
"description": "Native TypeScript implementation of the smooth-operator agent engine — an in-process, OpenAI-compatible agentic tool-calling loop with knowledge grounding. The TypeScript sibling of the Rust reference engine, the C# core, and the Python core.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|