@smooai/smooth-operator-core 0.10.0 → 0.10.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.
Files changed (85) hide show
  1. package/dist/agent.d.ts +276 -0
  2. package/dist/agent.d.ts.map +1 -0
  3. package/dist/agent.js +450 -0
  4. package/dist/agent.js.map +1 -0
  5. package/dist/cast.d.ts +81 -0
  6. package/dist/cast.d.ts.map +1 -0
  7. package/dist/cast.js +103 -0
  8. package/dist/cast.js.map +1 -0
  9. package/dist/checkpoint.d.ts +25 -0
  10. package/dist/checkpoint.d.ts.map +1 -0
  11. package/dist/checkpoint.js +23 -0
  12. package/dist/checkpoint.js.map +1 -0
  13. package/dist/compaction.d.ts +21 -0
  14. package/dist/compaction.d.ts.map +1 -0
  15. package/dist/compaction.js +50 -0
  16. package/dist/compaction.js.map +1 -0
  17. package/dist/cost.d.ts +34 -0
  18. package/dist/cost.d.ts.map +1 -0
  19. package/dist/cost.js +42 -0
  20. package/dist/cost.js.map +1 -0
  21. package/dist/extension/host.d.ts +199 -0
  22. package/dist/extension/host.d.ts.map +1 -0
  23. package/dist/extension/host.js +502 -0
  24. package/dist/extension/host.js.map +1 -0
  25. package/dist/extension/index.d.ts +36 -0
  26. package/dist/extension/index.d.ts.map +1 -0
  27. package/dist/extension/index.js +37 -0
  28. package/dist/extension/index.js.map +1 -0
  29. package/dist/extension/manifest.d.ts +111 -0
  30. package/dist/extension/manifest.d.ts.map +1 -0
  31. package/dist/extension/manifest.js +190 -0
  32. package/dist/extension/manifest.js.map +1 -0
  33. package/dist/extension/process.d.ts +118 -0
  34. package/dist/extension/process.d.ts.map +1 -0
  35. package/dist/extension/process.js +352 -0
  36. package/dist/extension/process.js.map +1 -0
  37. package/dist/extension/protocol.d.ts +254 -0
  38. package/dist/extension/protocol.d.ts.map +1 -0
  39. package/dist/extension/protocol.js +127 -0
  40. package/dist/extension/protocol.js.map +1 -0
  41. package/dist/extension/tool_proxy.d.ts +34 -0
  42. package/dist/extension/tool_proxy.d.ts.map +1 -0
  43. package/dist/extension/tool_proxy.js +48 -0
  44. package/dist/extension/tool_proxy.js.map +1 -0
  45. package/dist/humanGate.d.ts +44 -0
  46. package/dist/humanGate.d.ts.map +1 -0
  47. package/dist/humanGate.js +30 -0
  48. package/dist/humanGate.js.map +1 -0
  49. package/dist/index.d.ts +32 -0
  50. package/dist/index.d.ts.map +1 -0
  51. package/dist/index.js +21 -0
  52. package/dist/index.js.map +1 -0
  53. package/dist/knowledge.d.ts +30 -0
  54. package/dist/knowledge.d.ts.map +1 -0
  55. package/dist/knowledge.js +43 -0
  56. package/dist/knowledge.js.map +1 -0
  57. package/dist/llmProvider.d.ts +106 -0
  58. package/dist/llmProvider.d.ts.map +1 -0
  59. package/dist/llmProvider.js +160 -0
  60. package/dist/llmProvider.js.map +1 -0
  61. package/dist/memory.d.ts +23 -0
  62. package/dist/memory.d.ts.map +1 -0
  63. package/dist/memory.js +40 -0
  64. package/dist/memory.js.map +1 -0
  65. package/dist/rerank.d.ts +27 -0
  66. package/dist/rerank.d.ts.map +1 -0
  67. package/dist/rerank.js +45 -0
  68. package/dist/rerank.js.map +1 -0
  69. package/dist/thread.d.ts +43 -0
  70. package/dist/thread.d.ts.map +1 -0
  71. package/dist/thread.js +60 -0
  72. package/dist/thread.js.map +1 -0
  73. package/dist/toolSearch.d.ts +55 -0
  74. package/dist/toolSearch.d.ts.map +1 -0
  75. package/dist/toolSearch.js +110 -0
  76. package/dist/toolSearch.js.map +1 -0
  77. package/dist/vector.d.ts +36 -0
  78. package/dist/vector.d.ts.map +1 -0
  79. package/dist/vector.js +75 -0
  80. package/dist/vector.js.map +1 -0
  81. package/dist/workflow.d.ts +62 -0
  82. package/dist/workflow.d.ts.map +1 -0
  83. package/dist/workflow.js +109 -0
  84. package/dist/workflow.js.map +1 -0
  85. package/package.json +1 -1
@@ -0,0 +1,127 @@
1
+ /**
2
+ * SEP wire protocol — JSON-RPC 2.0 frames and typed method params/results.
3
+ *
4
+ * SEP (the Smooth Extension Protocol) is JSON-RPC 2.0 over ndjson on an extension
5
+ * subprocess's stdio. The canonical schemas live in the `smooth-operator` repo at
6
+ * `spec/extension/`; the types here are the TS engine host's view of that wire —
7
+ * the sibling of the Rust host's `extension/protocol.rs`. Field names are
8
+ * `snake_case` because they ARE the wire.
9
+ *
10
+ * The author-side `@smooai/smooth-extension-sdk` ships its own copy of these
11
+ * shapes; the host keeps them local rather than importing the SDK, which would
12
+ * invert the dependency (the engine is the lower layer the SDK's host consumers
13
+ * build on).
14
+ */
15
+ /** The SEP protocol version this host implements. Effective = min(host, ext). */
16
+ export const PROTOCOL_VERSION = 1;
17
+ /** SEP method names, centralized so the host and tests never spell one wrong. */
18
+ export const method = {
19
+ INITIALIZE: 'initialize',
20
+ SHUTDOWN: 'shutdown',
21
+ PING: 'ping',
22
+ EVENT: 'event',
23
+ HOOK: 'hook',
24
+ TOOL_EXECUTE: 'tool/execute',
25
+ TOOL_UPDATE: 'tool/update',
26
+ COMMAND_EXECUTE: 'command/execute',
27
+ COMMAND_COMPLETE: 'command/complete',
28
+ CANCEL: '$/cancel',
29
+ REGISTRY_UPDATE: 'registry/update',
30
+ TOOLS_SET_ACTIVE: 'tools/set_active',
31
+ EXEC_RUN: 'exec/run',
32
+ UI_REQUEST: 'ui/request',
33
+ LOG: 'log',
34
+ BUS_PUBLISH: 'bus/publish',
35
+ SESSION_SEND_MESSAGE: 'session/send_message',
36
+ SESSION_SEND_USER_MESSAGE: 'session/send_user_message',
37
+ SESSION_APPEND_ENTRY: 'session/append_entry',
38
+ };
39
+ /**
40
+ * JSON-RPC + SEP error codes (see `spec/extension/envelope.md`). Standard range
41
+ * plus the SEP extensions.
42
+ */
43
+ export const codes = {
44
+ ParseError: -32700,
45
+ InvalidRequest: -32600,
46
+ MethodNotFound: -32601,
47
+ InvalidParams: -32602,
48
+ InternalError: -32603,
49
+ /** A hook or policy vetoed the operation. */
50
+ Blocked: -32000,
51
+ /** `ui/request` in a headless/uncapable frontend. */
52
+ NoUI: -32001,
53
+ /** Extension acted beyond its granted trust. */
54
+ NotTrusted: -32002,
55
+ /** Command-tier action attempted from an event-tier context. */
56
+ ContextViolation: -32003,
57
+ /** Method requires a capability the handshake did not enable. */
58
+ CapabilityDisabled: -32004,
59
+ /** Request cancelled via `$/cancel`. */
60
+ Cancelled: -32800,
61
+ };
62
+ /** An error carrying a JSON-RPC error code, thrown/returned for a remote error. */
63
+ export class RpcError extends Error {
64
+ code;
65
+ data;
66
+ constructor(code, message, data) {
67
+ super(message);
68
+ this.code = code;
69
+ this.data = data;
70
+ this.name = 'RpcError';
71
+ }
72
+ toObject() {
73
+ return this.data === undefined ? { code: this.code, message: this.message } : { code: this.code, message: this.message, data: this.data };
74
+ }
75
+ }
76
+ /** Build a request frame. */
77
+ export function request(id, methodName, params) {
78
+ return { jsonrpc: '2.0', id, method: methodName, params };
79
+ }
80
+ /** Build a notification frame (no id, no reply expected). */
81
+ export function notification(methodName, params) {
82
+ return { jsonrpc: '2.0', method: methodName, params };
83
+ }
84
+ /** Build a success response frame echoing `id`. */
85
+ export function success(id, result) {
86
+ return { jsonrpc: '2.0', id, result };
87
+ }
88
+ /** Build an error response frame echoing `id`. */
89
+ export function errorResponse(id, error) {
90
+ return { jsonrpc: '2.0', id, error };
91
+ }
92
+ /** True when this frame is a request (has both `id` and `method`). */
93
+ export function isRequest(m) {
94
+ return m.id !== undefined && m.id !== null && m.method !== undefined;
95
+ }
96
+ /** True when this frame is a notification (has `method`, no `id`). */
97
+ export function isNotification(m) {
98
+ return (m.id === undefined || m.id === null) && m.method !== undefined;
99
+ }
100
+ /** True when this frame is a response (has `id`, no `method`). */
101
+ export function isResponse(m) {
102
+ return m.method === undefined && m.id !== undefined && m.id !== null;
103
+ }
104
+ /**
105
+ * Parse an untyped `hook` reply into a {@link HookOutcome}, or throw when it is
106
+ * malformed. Mirrors the Rust host's serde-tagged decode: a `modify` without a
107
+ * `patch`, or an unknown `action`, is rejected (the host then treats it as a
108
+ * failed hook step).
109
+ */
110
+ export function parseHookOutcome(value) {
111
+ if (typeof value !== 'object' || value === null)
112
+ throw new RpcError(codes.InvalidParams, 'hook outcome is not an object');
113
+ const action = value.action;
114
+ if (action === 'continue')
115
+ return { action: 'continue' };
116
+ if (action === 'block') {
117
+ const reason = value.reason;
118
+ return typeof reason === 'string' ? { action: 'block', reason } : { action: 'block' };
119
+ }
120
+ if (action === 'modify') {
121
+ if (!('patch' in value))
122
+ throw new RpcError(codes.InvalidParams, "hook 'modify' outcome missing patch");
123
+ return { action: 'modify', patch: value.patch };
124
+ }
125
+ throw new RpcError(codes.InvalidParams, `unknown hook action: ${String(action)}`);
126
+ }
127
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../src/extension/protocol.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * `ExtensionTool` — a core {@link Tool} backed by an extension subprocess. The TS
3
+ * sibling of the Rust host's `extension/tool_proxy.rs`.
4
+ *
5
+ * Registered tools appear to the agent as ordinary tools named `<extension>.<tool>`
6
+ * (the MCP convention). `execute` forwards to the extension over `tool/execute` and
7
+ * maps the reply back to a result string.
8
+ */
9
+ import type { Tool } from '../agent.js';
10
+ import type { ExtensionProcess } from './process.js';
11
+ import { type Context } from './protocol.js';
12
+ /**
13
+ * Upper bound (ms) for a single `tool/execute` round-trip. The agent applies its
14
+ * own per-tool timeout too; whichever is shorter wins in practice.
15
+ */
16
+ export declare const TOOL_EXECUTE_TIMEOUT_MS = 120000;
17
+ /** A tool exposed by an extension, adapted to the engine's {@link Tool} seam. */
18
+ export declare class ExtensionTool implements Tool {
19
+ private readonly process;
20
+ private readonly context;
21
+ /** `<extension>.<tool>` — what the agent/LLM sees. */
22
+ readonly name: string;
23
+ readonly description: string;
24
+ readonly parameters: Record<string, unknown>;
25
+ /** Bare tool name sent to the extension. */
26
+ private readonly bareName;
27
+ constructor(extName: string, reg: {
28
+ name: string;
29
+ description: string;
30
+ parameters: Record<string, unknown>;
31
+ }, process: ExtensionProcess, context: Context);
32
+ execute(args: Record<string, unknown>): Promise<string>;
33
+ }
34
+ //# sourceMappingURL=tool_proxy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool_proxy.d.ts","sourceRoot":"","sources":["../../src/extension/tool_proxy.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,KAAK,OAAO,EAAkC,MAAM,eAAe,CAAC;AAE7E;;;GAGG;AACH,eAAO,MAAM,uBAAuB,SAAU,CAAC;AAE/C,iFAAiF;AACjF,qBAAa,aAAc,YAAW,IAAI;IAWlC,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAX5B,sDAAsD;IACtD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7C,4CAA4C;IAC5C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAG9B,OAAO,EAAE,MAAM,EACf,GAAG,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,EAC9D,OAAO,EAAE,gBAAgB,EACzB,OAAO,EAAE,OAAO;IAQ/B,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;CAWhE"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * `ExtensionTool` — a core {@link Tool} backed by an extension subprocess. The TS
3
+ * sibling of the Rust host's `extension/tool_proxy.rs`.
4
+ *
5
+ * Registered tools appear to the agent as ordinary tools named `<extension>.<tool>`
6
+ * (the MCP convention). `execute` forwards to the extension over `tool/execute` and
7
+ * maps the reply back to a result string.
8
+ */
9
+ import { randomUUID } from 'node:crypto';
10
+ import { method } from './protocol.js';
11
+ /**
12
+ * Upper bound (ms) for a single `tool/execute` round-trip. The agent applies its
13
+ * own per-tool timeout too; whichever is shorter wins in practice.
14
+ */
15
+ export const TOOL_EXECUTE_TIMEOUT_MS = 120_000;
16
+ /** A tool exposed by an extension, adapted to the engine's {@link Tool} seam. */
17
+ export class ExtensionTool {
18
+ process;
19
+ context;
20
+ /** `<extension>.<tool>` — what the agent/LLM sees. */
21
+ name;
22
+ description;
23
+ parameters;
24
+ /** Bare tool name sent to the extension. */
25
+ bareName;
26
+ constructor(extName, reg, process, context) {
27
+ this.process = process;
28
+ this.context = context;
29
+ this.name = `${extName}.${reg.name}`;
30
+ this.bareName = reg.name;
31
+ this.description = reg.description;
32
+ this.parameters = reg.parameters;
33
+ }
34
+ async execute(args) {
35
+ const callId = randomUUID();
36
+ const params = { call_id: callId, tool: this.bareName, arguments: args, context: this.context };
37
+ const raw = (await this.process.request(method.TOOL_EXECUTE, params, TOOL_EXECUTE_TIMEOUT_MS));
38
+ if (typeof raw?.content !== 'string')
39
+ throw new Error('malformed tool/execute result: missing content');
40
+ if (raw.is_error)
41
+ throw new Error(raw.content);
42
+ // ponytail: `details` is dropped here — Tool.execute returns only a string.
43
+ // Surfacing structured details rides on tool-update/event wiring in a later
44
+ // phase; the field is preserved on ToolExecuteResult already.
45
+ return raw.content;
46
+ }
47
+ }
48
+ //# sourceMappingURL=tool_proxy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool_proxy.js","sourceRoot":"","sources":["../../src/extension/tool_proxy.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC,OAAO,EAAgB,MAAM,EAA0B,MAAM,eAAe,CAAC;AAE7E;;;GAGG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,OAAO,CAAC;AAE/C,iFAAiF;AACjF,MAAM,OAAO,aAAa;IAWD;IACA;IAXrB,sDAAsD;IAC7C,IAAI,CAAS;IACb,WAAW,CAAS;IACpB,UAAU,CAA0B;IAC7C,4CAA4C;IAC3B,QAAQ,CAAS;IAElC,YACI,OAAe,EACf,GAA+E,EAC9D,OAAyB,EACzB,OAAgB;QADhB,YAAO,GAAP,OAAO,CAAkB;QACzB,YAAO,GAAP,OAAO,CAAS;QAEjC,IAAI,CAAC,IAAI,GAAG,GAAG,OAAO,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;QACrC,IAAI,CAAC,QAAQ,GAAG,GAAG,CAAC,IAAI,CAAC;QACzB,IAAI,CAAC,WAAW,GAAG,GAAG,CAAC,WAAW,CAAC;QACnC,IAAI,CAAC,UAAU,GAAG,GAAG,CAAC,UAAU,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,IAA6B;QACvC,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;QAC5B,MAAM,MAAM,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC;QAChG,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,EAAE,uBAAuB,CAAC,CAAsB,CAAC;QACpH,IAAI,OAAO,GAAG,EAAE,OAAO,KAAK,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;QACxG,IAAI,GAAG,CAAC,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC/C,4EAA4E;QAC5E,4EAA4E;QAC5E,8DAA8D;QAC9D,OAAO,GAAG,CAAC,OAAO,CAAC;IACvB,CAAC;CACJ"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Human-in-the-loop approval — pause before a sensitive/write tool runs.
3
+ *
4
+ * Phase-2 sibling of the C# `HumanGate` (`dotnet/core`) and the Rust engine's
5
+ * confirmation hook. When a turn is about to run a tool the caller flagged as
6
+ * needing approval, the agent consults a {@link HumanGate} first. The gate IS the
7
+ * pause point — a UI gate awaits a real person (e.g. resolving a promise when a
8
+ * button is clicked); a programmatic gate decides immediately. A denial is never
9
+ * executed; the denial reason is fed back to the model as the tool result so the
10
+ * model can adapt. With no gate configured, behavior is unchanged.
11
+ */
12
+ /** The human's verdict on a tool call that required approval. */
13
+ export declare enum HumanDecision {
14
+ Approved = "approved",
15
+ Denied = "denied"
16
+ }
17
+ /**
18
+ * A request for human approval before the agent executes a sensitive/write tool.
19
+ * Mirrors the C# `HumanApprovalRequest` / the Rust engine's `HumanRequest::Confirm`.
20
+ */
21
+ export interface HumanApprovalRequest {
22
+ toolName: string;
23
+ arguments: Record<string, unknown>;
24
+ prompt: string;
25
+ }
26
+ /** The response to a {@link HumanApprovalRequest}. Mirrors the C# `HumanApprovalResponse`. */
27
+ export interface HumanApprovalResponse {
28
+ decision: HumanDecision;
29
+ reason?: string;
30
+ }
31
+ /** True when the decision is {@link HumanDecision.Approved}. */
32
+ export declare function isApproved(response: HumanApprovalResponse): boolean;
33
+ /** Build an approval. */
34
+ export declare function approve(): HumanApprovalResponse;
35
+ /** Build a denial carrying a reason the model will see. */
36
+ export declare function deny(reason: string): HumanApprovalResponse;
37
+ /**
38
+ * The human-in-the-loop seam: the agent consults it before running any tool that
39
+ * {@link AgentOptions.requiresApproval} flags. The implementation IS the pause
40
+ * point — wire it to a UI awaiting a real person, or decide programmatically.
41
+ * Mirrors the C# `IHumanGate` (here just an async function, the idiomatic TS seam).
42
+ */
43
+ export type HumanGate = (request: HumanApprovalRequest) => Promise<HumanApprovalResponse>;
44
+ //# sourceMappingURL=humanGate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"humanGate.d.ts","sourceRoot":"","sources":["../src/humanGate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,iEAAiE;AACjE,oBAAY,aAAa;IACrB,QAAQ,aAAa;IACrB,MAAM,WAAW;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,8FAA8F;AAC9F,MAAM,WAAW,qBAAqB;IAClC,QAAQ,EAAE,aAAa,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,gEAAgE;AAChE,wBAAgB,UAAU,CAAC,QAAQ,EAAE,qBAAqB,GAAG,OAAO,CAEnE;AAED,yBAAyB;AACzB,wBAAgB,OAAO,IAAI,qBAAqB,CAE/C;AAED,2DAA2D;AAC3D,wBAAgB,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,qBAAqB,CAE1D;AAED;;;;;GAKG;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,EAAE,oBAAoB,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Human-in-the-loop approval — pause before a sensitive/write tool runs.
3
+ *
4
+ * Phase-2 sibling of the C# `HumanGate` (`dotnet/core`) and the Rust engine's
5
+ * confirmation hook. When a turn is about to run a tool the caller flagged as
6
+ * needing approval, the agent consults a {@link HumanGate} first. The gate IS the
7
+ * pause point — a UI gate awaits a real person (e.g. resolving a promise when a
8
+ * button is clicked); a programmatic gate decides immediately. A denial is never
9
+ * executed; the denial reason is fed back to the model as the tool result so the
10
+ * model can adapt. With no gate configured, behavior is unchanged.
11
+ */
12
+ /** The human's verdict on a tool call that required approval. */
13
+ export var HumanDecision;
14
+ (function (HumanDecision) {
15
+ HumanDecision["Approved"] = "approved";
16
+ HumanDecision["Denied"] = "denied";
17
+ })(HumanDecision || (HumanDecision = {}));
18
+ /** True when the decision is {@link HumanDecision.Approved}. */
19
+ export function isApproved(response) {
20
+ return response.decision === HumanDecision.Approved;
21
+ }
22
+ /** Build an approval. */
23
+ export function approve() {
24
+ return { decision: HumanDecision.Approved };
25
+ }
26
+ /** Build a denial carrying a reason the model will see. */
27
+ export function deny(reason) {
28
+ return { decision: HumanDecision.Denied, reason };
29
+ }
30
+ //# sourceMappingURL=humanGate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"humanGate.js","sourceRoot":"","sources":["../src/humanGate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,iEAAiE;AACjE,MAAM,CAAN,IAAY,aAGX;AAHD,WAAY,aAAa;IACrB,sCAAqB,CAAA;IACrB,kCAAiB,CAAA;AACrB,CAAC,EAHW,aAAa,KAAb,aAAa,QAGxB;AAkBD,gEAAgE;AAChE,MAAM,UAAU,UAAU,CAAC,QAA+B;IACtD,OAAO,QAAQ,CAAC,QAAQ,KAAK,aAAa,CAAC,QAAQ,CAAC;AACxD,CAAC;AAED,yBAAyB;AACzB,MAAM,UAAU,OAAO;IACnB,OAAO,EAAE,QAAQ,EAAE,aAAa,CAAC,QAAQ,EAAE,CAAC;AAChD,CAAC;AAED,2DAA2D;AAC3D,MAAM,UAAU,IAAI,CAAC,MAAc;IAC/B,OAAO,EAAE,QAAQ,EAAE,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;AACtD,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @smooai/smooth-operator-core — a native, in-process agent engine for TypeScript.
3
+ *
4
+ * The Phase-0 TypeScript sibling of the Rust reference engine, the C# core, and
5
+ * the Python core: an agentic tool-calling loop over any OpenAI-compatible chat
6
+ * client, with in-memory knowledge grounding. See `docs/Architecture/TypeScript Core.md`.
7
+ */
8
+ export { delegateTool, SmoothAgent } from './agent.js';
9
+ export type { AgentOptions, AgentRunResponse, ChatChunk, ChatClientLike, StreamEvent, Tool } from './agent.js';
10
+ export { Cast, Clearance, makeRole, RoleKind } from './cast.js';
11
+ export type { OperatorRole } from './cast.js';
12
+ export { InMemoryCheckpointStore } from './checkpoint.js';
13
+ export type { Checkpoint, CheckpointStore } from './checkpoint.js';
14
+ export { CostTracker, DEFAULT_PRICING } from './cost.js';
15
+ export type { CostBudget, ModelPricing, Usage } from './cost.js';
16
+ export { approve, deny, HumanDecision, isApproved } from './humanGate.js';
17
+ export type { HumanApprovalRequest, HumanApprovalResponse, HumanGate } from './humanGate.js';
18
+ export { InMemoryKnowledge } from './knowledge.js';
19
+ export type { Knowledge, KnowledgeHit } from './knowledge.js';
20
+ export { MockLlmProvider, textResponse, toolCallResponse } from './llmProvider.js';
21
+ export type { LlmProvider, RecordedCall, ScriptedMessage, ScriptedUsage } from './llmProvider.js';
22
+ export { InMemoryMemory } from './memory.js';
23
+ export type { Memory, MemoryEntry } from './memory.js';
24
+ export { LexicalReranker, NoopReranker } from './rerank.js';
25
+ export type { Reranker } from './rerank.js';
26
+ export { SmoothAgentThread } from './thread.js';
27
+ export { MAX_MATCHES, TOOL_SEARCH_NAME, ToolSearch } from './toolSearch.js';
28
+ export { HashEmbedder, hashToken, VectorKnowledge } from './vector.js';
29
+ export type { Embedder } from './vector.js';
30
+ export { END, Workflow, WorkflowError } from './workflow.js';
31
+ export type { NodeFn, Router } from './workflow.js';
32
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACvD,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,SAAS,EAAE,cAAc,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAC/G,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAChE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC1D,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACzD,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC1E,YAAY,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC7F,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACnF,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAClG,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC5D,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,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;AACvE,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC7D,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @smooai/smooth-operator-core — a native, in-process agent engine for TypeScript.
3
+ *
4
+ * The Phase-0 TypeScript sibling of the Rust reference engine, the C# core, and
5
+ * the Python core: an agentic tool-calling loop over any OpenAI-compatible chat
6
+ * client, with in-memory knowledge grounding. See `docs/Architecture/TypeScript Core.md`.
7
+ */
8
+ export { delegateTool, SmoothAgent } from './agent.js';
9
+ export { Cast, Clearance, makeRole, RoleKind } from './cast.js';
10
+ export { InMemoryCheckpointStore } from './checkpoint.js';
11
+ export { CostTracker, DEFAULT_PRICING } from './cost.js';
12
+ export { approve, deny, HumanDecision, isApproved } from './humanGate.js';
13
+ export { InMemoryKnowledge } from './knowledge.js';
14
+ export { MockLlmProvider, textResponse, toolCallResponse } from './llmProvider.js';
15
+ export { InMemoryMemory } from './memory.js';
16
+ export { LexicalReranker, NoopReranker } from './rerank.js';
17
+ export { SmoothAgentThread } from './thread.js';
18
+ export { MAX_MATCHES, TOOL_SEARCH_NAME, ToolSearch } from './toolSearch.js';
19
+ export { HashEmbedder, hashToken, VectorKnowledge } from './vector.js';
20
+ export { END, Workflow, WorkflowError } from './workflow.js';
21
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEvD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAEhE,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAE1D,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAEzD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEnD,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEnF,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,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,QAAQ,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * In-memory knowledge base for the TypeScript smooth-operator core.
3
+ *
4
+ * A minimal lexical-overlap retriever — the Phase-0 sibling of the Rust engine's
5
+ * in-memory lexical store and the Python core's `InMemoryKnowledge`. Documents
6
+ * are scored by token overlap with the query; the top-k are returned. When
7
+ * nothing overlaps, the first k documents are returned anyway so the agent still
8
+ * has context to ground (or honestly decline) against.
9
+ */
10
+ export interface KnowledgeHit {
11
+ content: string;
12
+ source: string;
13
+ score: number;
14
+ }
15
+ /**
16
+ * A retriever: returns the most relevant documents for a query. Both the lexical
17
+ * {@link InMemoryKnowledge} and the embedding-backed `VectorKnowledge` satisfy
18
+ * this, so the agent accepts either.
19
+ */
20
+ export interface Knowledge {
21
+ query(query: string, topK?: number): KnowledgeHit[];
22
+ }
23
+ export declare class InMemoryKnowledge {
24
+ private readonly docs;
25
+ /** Add a document to the knowledge base. */
26
+ ingest(content: string, source: string): void;
27
+ /** Return up to `topK` documents, ranked by token overlap with `query`. */
28
+ query(query: string, topK?: number): KnowledgeHit[];
29
+ }
30
+ //# sourceMappingURL=knowledge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"knowledge.d.ts","sourceRoot":"","sources":["../src/knowledge.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,YAAY;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACtB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,YAAY,EAAE,CAAC;CACvD;AAWD,qBAAa,iBAAiB;IAC1B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;IAElC,4CAA4C;IAC5C,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAI7C,2EAA2E;IAC3E,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,SAAI,GAAG,YAAY,EAAE;CAsBjD"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * In-memory knowledge base for the TypeScript smooth-operator core.
3
+ *
4
+ * A minimal lexical-overlap retriever — the Phase-0 sibling of the Rust engine's
5
+ * in-memory lexical store and the Python core's `InMemoryKnowledge`. Documents
6
+ * are scored by token overlap with the query; the top-k are returned. When
7
+ * nothing overlaps, the first k documents are returned anyway so the agent still
8
+ * has context to ground (or honestly decline) against.
9
+ */
10
+ function tokenize(text) {
11
+ return text.toLowerCase().match(/[a-z0-9]+/g) ?? [];
12
+ }
13
+ export class InMemoryKnowledge {
14
+ docs = [];
15
+ /** Add a document to the knowledge base. */
16
+ ingest(content, source) {
17
+ this.docs.push({ content, source });
18
+ }
19
+ /** Return up to `topK` documents, ranked by token overlap with `query`. */
20
+ query(query, topK = 4) {
21
+ const qTokens = new Set(tokenize(query));
22
+ const scored = this.docs.map((doc) => {
23
+ const docTokens = new Set(tokenize(doc.content));
24
+ let overlap = 0;
25
+ for (const t of docTokens)
26
+ if (qTokens.has(t))
27
+ overlap++;
28
+ return { overlap, doc };
29
+ });
30
+ scored.sort((a, b) => b.overlap - a.overlap);
31
+ const hits = scored
32
+ .slice(0, topK)
33
+ .filter((s) => s.overlap > 0)
34
+ .map((s) => ({ content: s.doc.content, source: s.doc.source, score: s.overlap }));
35
+ if (hits.length === 0) {
36
+ // No lexical overlap — still hand the model the first k docs so it can
37
+ // ground or honestly decline, rather than retrieving nothing.
38
+ return this.docs.slice(0, topK).map((doc) => ({ content: doc.content, source: doc.source, score: 0 }));
39
+ }
40
+ return hits;
41
+ }
42
+ }
43
+ //# sourceMappingURL=knowledge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"knowledge.js","sourceRoot":"","sources":["../src/knowledge.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAsBH,SAAS,QAAQ,CAAC,IAAY;IAC1B,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;AACxD,CAAC;AAED,MAAM,OAAO,iBAAiB;IACT,IAAI,GAAU,EAAE,CAAC;IAElC,4CAA4C;IAC5C,MAAM,CAAC,OAAe,EAAE,MAAc;QAClC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;IACxC,CAAC;IAED,2EAA2E;IAC3E,KAAK,CAAC,KAAa,EAAE,IAAI,GAAG,CAAC;QACzB,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;QACzC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;YACjC,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;YACjD,IAAI,OAAO,GAAG,CAAC,CAAC;YAChB,KAAK,MAAM,CAAC,IAAI,SAAS;gBAAE,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;oBAAE,OAAO,EAAE,CAAC;YACzD,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;QAC5B,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC;QAE7C,MAAM,IAAI,GAAG,MAAM;aACd,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC;aACd,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC;aAC5B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAEtF,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACpB,uEAAuE;YACvE,8DAA8D;YAC9D,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAC3G,CAAC;QACD,OAAO,IAAI,CAAC;IAChB,CAAC;CACJ"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * An `LlmProvider` seam over the LLM call so the agentic loop can be unit-tested
3
+ * deterministically, without a live model or network.
4
+ *
5
+ * The agent already takes an injected OpenAI-compatible chat client
6
+ * ({@link ChatClientLike}). This module *formalizes* that as the provider seam —
7
+ * `LlmProvider` is an alias of `ChatClientLike`, so the existing `SmoothAgent`
8
+ * constructor is unchanged and backward compatible (the real `openai` SDK still
9
+ * satisfies it).
10
+ *
11
+ * It also ships a reusable, exported {@link MockLlmProvider} that replaces the
12
+ * ad-hoc fake clients the tests rolled by hand. The mock:
13
+ *
14
+ * - is constructed with a script of responses — plain text, tool-call responses,
15
+ * and errors;
16
+ * - returns them in FIFO order across calls;
17
+ * - records each request (the messages + tool specs it was given) so a test can
18
+ * assert on what the agent sent.
19
+ *
20
+ * This mirrors the BEHAVIOR of the Rust reference's `MockLlmClient`
21
+ * (`rust/smooth-operator-core/src/llm_provider.rs`). The mock implements both the
22
+ * non-streaming `create` seam (used by {@link SmoothAgent.run}) and the streaming
23
+ * `createStream` seam (used by {@link SmoothAgent.runStream}): it replays the SAME
24
+ * FIFO script as chunked deltas — text split into a few pieces, tool-call
25
+ * `arguments` split across two chunks to exercise the accumulator, and a final
26
+ * chunk carrying usage. Structured-output lands when that feature lands here.
27
+ */
28
+ import type { ChatChunk, ChatClientLike } from './agent.js';
29
+ /** The LLM call surface the agent loop depends on. Identical to {@link ChatClientLike}. */
30
+ export type LlmProvider = ChatClientLike;
31
+ /** An OpenAI-shaped assistant message — the `choices[0].message` the agent reads. */
32
+ export interface ScriptedMessage {
33
+ content: string | null;
34
+ tool_calls?: Array<{
35
+ id: string;
36
+ function: {
37
+ name: string;
38
+ arguments: string;
39
+ };
40
+ }> | null;
41
+ }
42
+ /** Build a plain-text scripted response (no tool calls). */
43
+ export declare function textResponse(content: string): ScriptedMessage;
44
+ /** Build a scripted response that requests a single tool call. */
45
+ export declare function toolCallResponse(id: string, name: string, args: string): ScriptedMessage;
46
+ /** One request the mock received, captured for assertions. */
47
+ export interface RecordedCall {
48
+ /** The full request body passed to `chat.completions.create`. */
49
+ body: Record<string, unknown>;
50
+ /** The messages passed on this call. */
51
+ messages: Array<Record<string, unknown>>;
52
+ /** The tool specs offered to the model, if any. */
53
+ tools?: Array<Record<string, unknown>>;
54
+ }
55
+ /** Optional token usage to attach to a scripted response (the model/gateway reports it). */
56
+ export interface ScriptedUsage {
57
+ prompt_tokens?: number;
58
+ completion_tokens?: number;
59
+ }
60
+ /**
61
+ * A deterministic {@link LlmProvider} for tests. Script the responses it should
62
+ * return (FIFO), drive your code, then assert on {@link MockLlmProvider.calls}.
63
+ *
64
+ * Construct empty and build up fluently (`pushText` / `pushToolCall` / `pushError`),
65
+ * or pass an initial script of {@link ScriptedMessage}s.
66
+ *
67
+ * @example
68
+ * const mock = new MockLlmProvider();
69
+ * mock.pushText('hello there');
70
+ * const agent = new SmoothAgent(mock, {});
71
+ * const result = await agent.run('hi');
72
+ * expect(result.text).toBe('hello there');
73
+ * expect(mock.callCount).toBe(1);
74
+ */
75
+ export declare class MockLlmProvider implements ChatClientLike {
76
+ private readonly script;
77
+ private readonly recorded;
78
+ constructor(script?: ScriptedMessage[]);
79
+ /** Queue a raw OpenAI-shaped assistant message (with optional usage) for the next call. */
80
+ pushResponse(message: ScriptedMessage, usage?: ScriptedUsage): this;
81
+ /** Queue a plain-text response (with optional usage) for the next call. */
82
+ pushText(content: string, usage?: ScriptedUsage): this;
83
+ /** Queue a single-tool-call response (with optional usage) for the next call. */
84
+ pushToolCall(id: string, name: string, args: string, usage?: ScriptedUsage): this;
85
+ /** Queue an error to be thrown on the next call. */
86
+ pushError(message: string): this;
87
+ /** Every request the mock has received so far, in order. */
88
+ get calls(): readonly RecordedCall[];
89
+ /** Number of requests received. */
90
+ get callCount(): number;
91
+ /** The most recent request, if any. */
92
+ get lastCall(): RecordedCall | undefined;
93
+ private record;
94
+ readonly chat: {
95
+ completions: {
96
+ create: (body: Record<string, unknown>) => Promise<{
97
+ choices: {
98
+ message: ScriptedMessage;
99
+ }[];
100
+ usage: ScriptedUsage | null;
101
+ }>;
102
+ createStream: (body: Record<string, unknown>) => AsyncIterable<ChatChunk>;
103
+ };
104
+ };
105
+ }
106
+ //# sourceMappingURL=llmProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llmProvider.d.ts","sourceRoot":"","sources":["../src/llmProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5D,2FAA2F;AAC3F,MAAM,MAAM,WAAW,GAAG,cAAc,CAAC;AAEzC,qFAAqF;AACrF,MAAM,WAAW,eAAe;IAC5B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,CAAC,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC,GAAG,IAAI,CAAC;CAC5F;AAED,4DAA4D;AAC5D,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,CAE7D;AAED,kEAAkE;AAClE,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,eAAe,CAExF;AAED,8DAA8D;AAC9D,MAAM,WAAW,YAAY;IACzB,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,wCAAwC;IACxC,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACzC,mDAAmD;IACnD,KAAK,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC1C;AAED,4FAA4F;AAC5F,MAAM,WAAW,aAAa;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAKD;;;;;;;;;;;;;;GAcG;AACH,qBAAa,eAAgB,YAAW,cAAc;IAClD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IACxC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsB;gBAEnC,MAAM,GAAE,eAAe,EAAO;IAM1C,2FAA2F;IAC3F,YAAY,CAAC,OAAO,EAAE,eAAe,EAAE,KAAK,CAAC,EAAE,aAAa,GAAG,IAAI;IAKnE,2EAA2E;IAC3E,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,aAAa,GAAG,IAAI;IAItD,iFAAiF;IACjF,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,aAAa,GAAG,IAAI;IAIjF,oDAAoD;IACpD,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAOhC,4DAA4D;IAC5D,IAAI,KAAK,IAAI,SAAS,YAAY,EAAE,CAEnC;IAED,mCAAmC;IACnC,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,uCAAuC;IACvC,IAAI,QAAQ,IAAI,YAAY,GAAG,SAAS,CAEvC;IAID,OAAO,CAAC,MAAM;IAQd,QAAQ,CAAC,IAAI;;2BAEgB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;iCAcvB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,aAAa,CAAC,SAAS,CAAC;;MAiC7E;CACL"}