@harny/sdk 0.1.2 → 0.1.4
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/cjs/agent/adapters.d.ts +167 -0
- package/dist/cjs/agent/adapters.js +557 -0
- package/dist/cjs/agent/adapters.js.map +1 -0
- package/dist/cjs/agent/hooks.d.ts +52 -0
- package/dist/cjs/agent/hooks.js +41 -0
- package/dist/cjs/agent/hooks.js.map +1 -0
- package/dist/cjs/agent/index.d.ts +34 -0
- package/dist/cjs/agent/index.js +62 -0
- package/dist/cjs/agent/index.js.map +1 -0
- package/dist/cjs/agent/loop.d.ts +401 -0
- package/dist/cjs/agent/loop.js +1252 -0
- package/dist/cjs/agent/loop.js.map +1 -0
- package/dist/cjs/agent/roster.d.ts +62 -0
- package/dist/cjs/agent/roster.js +149 -0
- package/dist/cjs/agent/roster.js.map +1 -0
- package/dist/cjs/agent/session.d.ts +106 -0
- package/dist/cjs/agent/session.js +261 -0
- package/dist/cjs/agent/session.js.map +1 -0
- package/dist/cjs/agent/spend.d.ts +39 -0
- package/dist/cjs/agent/spend.js +70 -0
- package/dist/cjs/agent/spend.js.map +1 -0
- package/dist/cjs/agent/tools.d.ts +83 -0
- package/dist/cjs/agent/tools.js +212 -0
- package/dist/cjs/agent/tools.js.map +1 -0
- package/dist/cjs/agent/tracing.d.ts +72 -0
- package/dist/cjs/agent/tracing.js +128 -0
- package/dist/cjs/agent/tracing.js.map +1 -0
- package/dist/cjs/agent/util.d.ts +60 -0
- package/dist/cjs/agent/util.js +188 -0
- package/dist/cjs/agent/util.js.map +1 -0
- package/dist/cjs/conflictQuestion.d.ts +137 -0
- package/dist/cjs/conflictQuestion.js +356 -0
- package/dist/cjs/conflictQuestion.js.map +1 -0
- package/dist/cjs/index.d.ts +950 -0
- package/dist/cjs/index.js +1124 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/memoryV1.d.ts +121 -0
- package/dist/cjs/memoryV1.js +132 -0
- package/dist/cjs/memoryV1.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/esm/agent/adapters.d.ts +167 -0
- package/dist/esm/agent/adapters.js +543 -0
- package/dist/esm/agent/adapters.js.map +1 -0
- package/dist/esm/agent/hooks.d.ts +52 -0
- package/dist/esm/agent/hooks.js +36 -0
- package/dist/esm/agent/hooks.js.map +1 -0
- package/dist/esm/agent/index.d.ts +34 -0
- package/dist/esm/agent/index.js +28 -0
- package/dist/esm/agent/index.js.map +1 -0
- package/dist/esm/agent/loop.d.ts +401 -0
- package/dist/esm/agent/loop.js +1243 -0
- package/dist/esm/agent/loop.js.map +1 -0
- package/dist/esm/agent/roster.d.ts +62 -0
- package/dist/esm/agent/roster.js +143 -0
- package/dist/esm/agent/roster.js.map +1 -0
- package/dist/esm/agent/session.d.ts +106 -0
- package/dist/esm/agent/session.js +221 -0
- package/dist/esm/agent/session.js.map +1 -0
- package/dist/esm/agent/spend.d.ts +39 -0
- package/dist/esm/agent/spend.js +65 -0
- package/dist/esm/agent/spend.js.map +1 -0
- package/dist/esm/agent/tools.d.ts +83 -0
- package/dist/esm/agent/tools.js +205 -0
- package/dist/esm/agent/tools.js.map +1 -0
- package/dist/esm/agent/tracing.d.ts +72 -0
- package/dist/esm/agent/tracing.js +119 -0
- package/dist/esm/agent/tracing.js.map +1 -0
- package/dist/esm/agent/util.d.ts +60 -0
- package/dist/esm/agent/util.js +168 -0
- package/dist/esm/agent/util.js.map +1 -0
- package/dist/esm/conflictQuestion.d.ts +137 -0
- package/dist/esm/conflictQuestion.js +346 -0
- package/dist/esm/conflictQuestion.js.map +1 -0
- package/dist/esm/index.d.ts +950 -0
- package/dist/esm/index.js +1072 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/memoryV1.d.ts +121 -0
- package/dist/esm/memoryV1.js +124 -0
- package/dist/esm/memoryV1.js.map +1 -0
- package/dist/esm/package.json +1 -0
- package/package.json +3 -4
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Short-term conversation memory for the agent, kept in the business's own deploy.
|
|
4
|
+
*
|
|
5
|
+
* The agent remembers the last turns of a conversation so a follow-up ("move
|
|
6
|
+
* it to 4") makes sense. Those turns live HERE, in a store the business runs;
|
|
7
|
+
* they are never sent to Harny. Swap the store by implementing `SessionStore`
|
|
8
|
+
* (three methods) over the business's own database.
|
|
9
|
+
*
|
|
10
|
+
* The agent's default is `MemorySessionStore`, which keeps conversations
|
|
11
|
+
* until the process stops. `FileSessionStore` (Node only) writes one JSON
|
|
12
|
+
* file per session, readable only by its owner, with an atomic replace, so a
|
|
13
|
+
* crash never leaves half a file. Session ids are hashed into file names, so
|
|
14
|
+
* an id can never escape the directory. The file format is the one the Python
|
|
15
|
+
* SDK writes, so either SDK can read the other's files.
|
|
16
|
+
*
|
|
17
|
+
* Each assistant turn also carries a short note of the actions the agent
|
|
18
|
+
* performed in it (`ActionNote`: action, record id, time, and for an event its
|
|
19
|
+
* title and start). The next run puts those notes in front of the model, so
|
|
20
|
+
* "undo that" in a later message finds the record id. The notes stay in this
|
|
21
|
+
* store with the conversation; they are never sent to Harny. A store that
|
|
22
|
+
* keeps only `role` and `content` still works: it just loses the notes.
|
|
23
|
+
*/
|
|
24
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
25
|
+
if (k2 === undefined) k2 = k;
|
|
26
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
27
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
28
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
29
|
+
}
|
|
30
|
+
Object.defineProperty(o, k2, desc);
|
|
31
|
+
}) : (function(o, m, k, k2) {
|
|
32
|
+
if (k2 === undefined) k2 = k;
|
|
33
|
+
o[k2] = m[k];
|
|
34
|
+
}));
|
|
35
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
36
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
37
|
+
}) : function(o, v) {
|
|
38
|
+
o["default"] = v;
|
|
39
|
+
});
|
|
40
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
41
|
+
var ownKeys = function(o) {
|
|
42
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
43
|
+
var ar = [];
|
|
44
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
45
|
+
return ar;
|
|
46
|
+
};
|
|
47
|
+
return ownKeys(o);
|
|
48
|
+
};
|
|
49
|
+
return function (mod) {
|
|
50
|
+
if (mod && mod.__esModule) return mod;
|
|
51
|
+
var result = {};
|
|
52
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
53
|
+
__setModuleDefault(result, mod);
|
|
54
|
+
return result;
|
|
55
|
+
};
|
|
56
|
+
})();
|
|
57
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
58
|
+
exports.FileSessionStore = exports.MemorySessionStore = exports.Turn = exports.ActionNote = void 0;
|
|
59
|
+
const util_js_1 = require("./util.js");
|
|
60
|
+
function toDate(value) {
|
|
61
|
+
if (value instanceof Date)
|
|
62
|
+
return value;
|
|
63
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
64
|
+
const parsed = new Date(value);
|
|
65
|
+
if (!Number.isNaN(parsed.getTime()))
|
|
66
|
+
return parsed;
|
|
67
|
+
}
|
|
68
|
+
return new Date();
|
|
69
|
+
}
|
|
70
|
+
function optionalText(value) {
|
|
71
|
+
return value === null || value === undefined ? null : String(value);
|
|
72
|
+
}
|
|
73
|
+
/** One action the agent performed, as the conversation remembers it. */
|
|
74
|
+
class ActionNote {
|
|
75
|
+
constructor(init) {
|
|
76
|
+
this.action = init.action;
|
|
77
|
+
this.recordId = init.recordId;
|
|
78
|
+
this.at = init.at === undefined ? new Date() : toDate(init.at);
|
|
79
|
+
this.outcome = init.outcome ?? "completed";
|
|
80
|
+
this.reverses = init.reverses ?? null;
|
|
81
|
+
this.title = init.title ?? null;
|
|
82
|
+
this.start = init.start ?? null;
|
|
83
|
+
this.confirmedInApp = init.confirmedInApp ?? false;
|
|
84
|
+
}
|
|
85
|
+
/** The stored form (the Python SDK's field names). */
|
|
86
|
+
toJSON() {
|
|
87
|
+
return {
|
|
88
|
+
action: this.action,
|
|
89
|
+
record_id: this.recordId,
|
|
90
|
+
at: this.at.toISOString(),
|
|
91
|
+
outcome: this.outcome,
|
|
92
|
+
reverses: this.reverses,
|
|
93
|
+
title: this.title,
|
|
94
|
+
start: this.start,
|
|
95
|
+
confirmed_in_app: this.confirmedInApp,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
static fromJSON(raw) {
|
|
99
|
+
if (!(0, util_js_1.isPlainObject)(raw) || typeof raw.action !== "string" || raw.record_id === undefined || raw.record_id === null) {
|
|
100
|
+
throw new Error("a stored action note needs action and record_id");
|
|
101
|
+
}
|
|
102
|
+
return new ActionNote({
|
|
103
|
+
action: raw.action,
|
|
104
|
+
recordId: String(raw.record_id),
|
|
105
|
+
at: raw.at === undefined || raw.at === null ? undefined : toDate(raw.at),
|
|
106
|
+
outcome: raw.outcome === undefined || raw.outcome === null ? undefined : String(raw.outcome),
|
|
107
|
+
reverses: optionalText(raw.reverses),
|
|
108
|
+
title: optionalText(raw.title),
|
|
109
|
+
start: optionalText(raw.start),
|
|
110
|
+
confirmedInApp: Boolean(raw.confirmed_in_app),
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
exports.ActionNote = ActionNote;
|
|
115
|
+
class Turn {
|
|
116
|
+
constructor(init) {
|
|
117
|
+
if (init.role !== "user" && init.role !== "assistant")
|
|
118
|
+
throw new Error("a turn's role is user or assistant");
|
|
119
|
+
if (typeof init.content !== "string")
|
|
120
|
+
throw new Error("a turn's content is text");
|
|
121
|
+
this.role = init.role;
|
|
122
|
+
this.content = init.content;
|
|
123
|
+
this.at = init.at === undefined ? new Date() : toDate(init.at);
|
|
124
|
+
this.actions = [...(init.actions ?? [])];
|
|
125
|
+
}
|
|
126
|
+
toJSON() {
|
|
127
|
+
return {
|
|
128
|
+
role: this.role,
|
|
129
|
+
content: this.content,
|
|
130
|
+
at: this.at.toISOString(),
|
|
131
|
+
actions: this.actions.map((note) => note.toJSON()),
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
static fromJSON(raw) {
|
|
135
|
+
if (!(0, util_js_1.isPlainObject)(raw))
|
|
136
|
+
throw new Error("a stored turn is an object");
|
|
137
|
+
const actions = Array.isArray(raw.actions) ? raw.actions.map((a) => ActionNote.fromJSON(a)) : [];
|
|
138
|
+
return new Turn({
|
|
139
|
+
role: raw.role,
|
|
140
|
+
content: raw.content,
|
|
141
|
+
at: raw.at === undefined || raw.at === null ? undefined : toDate(raw.at),
|
|
142
|
+
actions,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
exports.Turn = Turn;
|
|
147
|
+
function lastTurns(turns, limit) {
|
|
148
|
+
return limit ? turns.slice(-limit) : turns;
|
|
149
|
+
}
|
|
150
|
+
/** In-process store: the agent's default. Kept until the process stops. */
|
|
151
|
+
class MemorySessionStore {
|
|
152
|
+
constructor(options = {}) {
|
|
153
|
+
this.data = new Map();
|
|
154
|
+
this.maxTurns = options.maxTurns ?? 200;
|
|
155
|
+
}
|
|
156
|
+
async load(sessionId, options = {}) {
|
|
157
|
+
return lastTurns([...(this.data.get(sessionId) ?? [])], options.limit);
|
|
158
|
+
}
|
|
159
|
+
async append(sessionId, turns) {
|
|
160
|
+
const kept = [...(this.data.get(sessionId) ?? []), ...turns].slice(-this.maxTurns);
|
|
161
|
+
this.data.set(sessionId, kept);
|
|
162
|
+
}
|
|
163
|
+
async clear(sessionId) {
|
|
164
|
+
this.data.delete(sessionId);
|
|
165
|
+
}
|
|
166
|
+
sessionIds() {
|
|
167
|
+
return [...this.data.keys()];
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
exports.MemorySessionStore = MemorySessionStore;
|
|
171
|
+
/** One JSON file per session under `directory`, readable only by its owner (Node only). */
|
|
172
|
+
class FileSessionStore {
|
|
173
|
+
constructor(directory, options = {}) {
|
|
174
|
+
this.queue = Promise.resolve();
|
|
175
|
+
this.modules = null;
|
|
176
|
+
if (!directory)
|
|
177
|
+
throw new Error("directory is required");
|
|
178
|
+
this.directory = directory;
|
|
179
|
+
this.maxTurns = options.maxTurns ?? 200;
|
|
180
|
+
}
|
|
181
|
+
node() {
|
|
182
|
+
this.modules ?? (this.modules = Promise.all([Promise.resolve().then(() => __importStar(require("node:fs/promises"))), Promise.resolve().then(() => __importStar(require("node:path")))]));
|
|
183
|
+
return this.modules;
|
|
184
|
+
}
|
|
185
|
+
/** One operation at a time, so two appends never interleave a read and a write. */
|
|
186
|
+
locked(operation) {
|
|
187
|
+
const next = this.queue.then(operation, operation);
|
|
188
|
+
this.queue = next.catch(() => undefined);
|
|
189
|
+
return next;
|
|
190
|
+
}
|
|
191
|
+
async file(sessionId) {
|
|
192
|
+
const [, path] = await this.node();
|
|
193
|
+
return path.join(this.directory, `${await (0, util_js_1.sha256Hex)(sessionId)}.json`);
|
|
194
|
+
}
|
|
195
|
+
async read(sessionId) {
|
|
196
|
+
const [fs] = await this.node();
|
|
197
|
+
let raw;
|
|
198
|
+
try {
|
|
199
|
+
raw = JSON.parse(await fs.readFile(await this.file(sessionId), "utf8"));
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
return [];
|
|
203
|
+
}
|
|
204
|
+
const turns = (0, util_js_1.isPlainObject)(raw) && Array.isArray(raw.turns) ? raw.turns : [];
|
|
205
|
+
return turns.map((item) => Turn.fromJSON(item));
|
|
206
|
+
}
|
|
207
|
+
async write(sessionId, turns) {
|
|
208
|
+
const [fs, path] = await this.node();
|
|
209
|
+
await fs.mkdir(this.directory, { recursive: true });
|
|
210
|
+
const tmp = path.join(this.directory, `.tmp-${(0, util_js_1.randomHex)(8)}.json`);
|
|
211
|
+
const payload = { session_id: sessionId, turns: turns.map((t) => t.toJSON()) };
|
|
212
|
+
try {
|
|
213
|
+
await fs.writeFile(tmp, JSON.stringify(payload), { encoding: "utf8", flag: "wx", mode: 0o600 });
|
|
214
|
+
await fs.rename(tmp, await this.file(sessionId));
|
|
215
|
+
}
|
|
216
|
+
finally {
|
|
217
|
+
await fs.rm(tmp, { force: true });
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
load(sessionId, options = {}) {
|
|
221
|
+
return this.locked(async () => lastTurns(await this.read(sessionId), options.limit));
|
|
222
|
+
}
|
|
223
|
+
append(sessionId, turns) {
|
|
224
|
+
return this.locked(async () => {
|
|
225
|
+
const kept = [...(await this.read(sessionId)), ...turns].slice(-this.maxTurns);
|
|
226
|
+
await this.write(sessionId, kept);
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
clear(sessionId) {
|
|
230
|
+
return this.locked(async () => {
|
|
231
|
+
const [fs] = await this.node();
|
|
232
|
+
await fs.rm(await this.file(sessionId), { force: true });
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
sessionIds() {
|
|
236
|
+
return this.locked(async () => {
|
|
237
|
+
const [fs, path] = await this.node();
|
|
238
|
+
let names;
|
|
239
|
+
try {
|
|
240
|
+
names = (await fs.readdir(this.directory)).filter((n) => n.endsWith(".json")).sort();
|
|
241
|
+
}
|
|
242
|
+
catch {
|
|
243
|
+
return [];
|
|
244
|
+
}
|
|
245
|
+
const ids = [];
|
|
246
|
+
for (const name of names) {
|
|
247
|
+
try {
|
|
248
|
+
const raw = JSON.parse(await fs.readFile(path.join(this.directory, name), "utf8"));
|
|
249
|
+
if ((0, util_js_1.isPlainObject)(raw) && raw.session_id !== undefined)
|
|
250
|
+
ids.push(String(raw.session_id));
|
|
251
|
+
}
|
|
252
|
+
catch {
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return ids;
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
exports.FileSessionStore = FileSessionStore;
|
|
261
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../../src/agent/session.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A spend cap per run, so one chatty conversation cannot run up the model bill.
|
|
3
|
+
*
|
|
4
|
+
* The cap is checked before every model call and after it. When the cap is
|
|
5
|
+
* reached the run stops; nothing already done is undone, and the run result
|
|
6
|
+
* says `stoppedReason === "spend_cap"`.
|
|
7
|
+
*
|
|
8
|
+
* Dollars need a price. The roster carries list prices for most entries; for
|
|
9
|
+
* an entry without one, state the price in the agent's options, or rely on
|
|
10
|
+
* the token cap. A run always has a cap: when no token cap is set and no
|
|
11
|
+
* dollar cap can apply (no cap at all, or a dollar cap on a model without a
|
|
12
|
+
* price), the run stops at `FALLBACK_MAX_TOKENS` tokens, and the agent's model
|
|
13
|
+
* notes say so.
|
|
14
|
+
*/
|
|
15
|
+
import { Usage } from "./adapters.js";
|
|
16
|
+
/** The token cap a run falls back to when no other cap can apply. */
|
|
17
|
+
export declare const FALLBACK_MAX_TOKENS = 100000;
|
|
18
|
+
export declare class SpendCap {
|
|
19
|
+
readonly maxUsd: number | null;
|
|
20
|
+
readonly maxTokens: number | null;
|
|
21
|
+
constructor(init?: {
|
|
22
|
+
maxUsd?: number | null;
|
|
23
|
+
maxTokens?: number | null;
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
export declare class SpendMeter {
|
|
27
|
+
readonly cap: SpendCap;
|
|
28
|
+
readonly inputPerMtok: number | null;
|
|
29
|
+
readonly outputPerMtok: number | null;
|
|
30
|
+
readonly usage: Usage;
|
|
31
|
+
constructor(cap: SpendCap, inputPerMtok?: number | null, outputPerMtok?: number | null);
|
|
32
|
+
get priced(): boolean;
|
|
33
|
+
get costUsd(): number | null;
|
|
34
|
+
get usdCapEnforced(): boolean;
|
|
35
|
+
/** The token cap in force: the cap's own, else the fallback when no dollar cap can apply. */
|
|
36
|
+
get maxTokens(): number | null;
|
|
37
|
+
record(usage: Usage): void;
|
|
38
|
+
exhausted(): boolean;
|
|
39
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* A spend cap per run, so one chatty conversation cannot run up the model bill.
|
|
4
|
+
*
|
|
5
|
+
* The cap is checked before every model call and after it. When the cap is
|
|
6
|
+
* reached the run stops; nothing already done is undone, and the run result
|
|
7
|
+
* says `stoppedReason === "spend_cap"`.
|
|
8
|
+
*
|
|
9
|
+
* Dollars need a price. The roster carries list prices for most entries; for
|
|
10
|
+
* an entry without one, state the price in the agent's options, or rely on
|
|
11
|
+
* the token cap. A run always has a cap: when no token cap is set and no
|
|
12
|
+
* dollar cap can apply (no cap at all, or a dollar cap on a model without a
|
|
13
|
+
* price), the run stops at `FALLBACK_MAX_TOKENS` tokens, and the agent's model
|
|
14
|
+
* notes say so.
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.SpendMeter = exports.SpendCap = exports.FALLBACK_MAX_TOKENS = void 0;
|
|
18
|
+
const adapters_js_1 = require("./adapters.js");
|
|
19
|
+
/** The token cap a run falls back to when no other cap can apply. */
|
|
20
|
+
exports.FALLBACK_MAX_TOKENS = 100000;
|
|
21
|
+
class SpendCap {
|
|
22
|
+
constructor(init = {}) {
|
|
23
|
+
this.maxUsd = init.maxUsd ?? null;
|
|
24
|
+
this.maxTokens = init.maxTokens ?? null;
|
|
25
|
+
if (this.maxUsd !== null && !(this.maxUsd > 0))
|
|
26
|
+
throw new Error("maxUsd must be positive");
|
|
27
|
+
if (this.maxTokens !== null && !(this.maxTokens > 0))
|
|
28
|
+
throw new Error("maxTokens must be positive");
|
|
29
|
+
Object.freeze(this);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
exports.SpendCap = SpendCap;
|
|
33
|
+
class SpendMeter {
|
|
34
|
+
constructor(cap, inputPerMtok = null, outputPerMtok = null) {
|
|
35
|
+
this.cap = cap;
|
|
36
|
+
this.inputPerMtok = inputPerMtok;
|
|
37
|
+
this.outputPerMtok = outputPerMtok;
|
|
38
|
+
this.usage = new adapters_js_1.Usage();
|
|
39
|
+
}
|
|
40
|
+
get priced() {
|
|
41
|
+
return this.inputPerMtok !== null && this.outputPerMtok !== null;
|
|
42
|
+
}
|
|
43
|
+
get costUsd() {
|
|
44
|
+
if (!this.priced)
|
|
45
|
+
return null;
|
|
46
|
+
return ((this.usage.inputTokens * Number(this.inputPerMtok)) / 1000000 +
|
|
47
|
+
(this.usage.outputTokens * Number(this.outputPerMtok)) / 1000000);
|
|
48
|
+
}
|
|
49
|
+
get usdCapEnforced() {
|
|
50
|
+
return this.cap.maxUsd !== null && this.priced;
|
|
51
|
+
}
|
|
52
|
+
/** The token cap in force: the cap's own, else the fallback when no dollar cap can apply. */
|
|
53
|
+
get maxTokens() {
|
|
54
|
+
if (this.cap.maxTokens !== null)
|
|
55
|
+
return this.cap.maxTokens;
|
|
56
|
+
return this.usdCapEnforced ? null : exports.FALLBACK_MAX_TOKENS;
|
|
57
|
+
}
|
|
58
|
+
record(usage) {
|
|
59
|
+
this.usage.add(usage);
|
|
60
|
+
}
|
|
61
|
+
exhausted() {
|
|
62
|
+
const limit = this.maxTokens;
|
|
63
|
+
if (limit !== null && this.usage.totalTokens >= limit)
|
|
64
|
+
return true;
|
|
65
|
+
const cost = this.costUsd;
|
|
66
|
+
return this.cap.maxUsd !== null && cost !== null && cost >= this.cap.maxUsd;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
exports.SpendMeter = SpendMeter;
|
|
70
|
+
//# sourceMappingURL=spend.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spend.js","sourceRoot":"","sources":["../../../src/agent/spend.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;;;AAEH,+CAAsC;AAEtC,qEAAqE;AACxD,QAAA,mBAAmB,GAAG,MAAO,CAAC;AAE3C,MAAa,QAAQ;IAIjB,YAAY,OAA8D,EAAE;QACxE,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC;QAClC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC;QACxC,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;QAC3F,IAAI,IAAI,CAAC,SAAS,KAAK,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QACpG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;CACJ;AAXD,4BAWC;AAED,MAAa,UAAU;IAGnB,YACa,GAAa,EACb,eAA8B,IAAI,EAClC,gBAA+B,IAAI;QAFnC,QAAG,GAAH,GAAG,CAAU;QACb,iBAAY,GAAZ,YAAY,CAAsB;QAClC,kBAAa,GAAb,aAAa,CAAsB;QALvC,UAAK,GAAG,IAAI,mBAAK,EAAE,CAAC;IAM1B,CAAC;IAEJ,IAAI,MAAM;QACN,OAAO,IAAI,CAAC,YAAY,KAAK,IAAI,IAAI,IAAI,CAAC,aAAa,KAAK,IAAI,CAAC;IACrE,CAAC;IAED,IAAI,OAAO;QACP,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QAC9B,OAAO,CACH,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,GAAG,OAAS;YAChE,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,GAAG,OAAS,CACrE,CAAC;IACN,CAAC;IAED,IAAI,cAAc;QACd,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,KAAK,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC;IACnD,CAAC;IAED,6FAA6F;IAC7F,IAAI,SAAS;QACT,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC;QAC3D,OAAO,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,2BAAmB,CAAC;IAC5D,CAAC;IAED,MAAM,CAAC,KAAY;QACf,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;IAED,SAAS;QACL,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC;QAC7B,IAAI,KAAK,KAAK,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,IAAI,KAAK;YAAE,OAAO,IAAI,CAAC;QACnE,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC;QAC1B,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC;IAChF,CAAC;CACJ;AAzCD,gCAyCC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The agent's one door to Harny, and the tools it offers the model.
|
|
3
|
+
*
|
|
4
|
+
* `HarnyTools` wraps a Harny client and exposes exactly six named calls:
|
|
5
|
+
* `assembleContext`, `act`, `undo`, `getSourceItem`, `listArrivals` and
|
|
6
|
+
* `confirm`. The agent loop holds this facade, never the client, so it cannot
|
|
7
|
+
* reach any other Harny call. In particular it has no way to write the
|
|
8
|
+
* conversation into Harny's memory: a chat turn, and above all an AI turn, is
|
|
9
|
+
* never ingested. The conversation stays in the business's own session store.
|
|
10
|
+
*
|
|
11
|
+
* `confirm` is on the facade for the HOST (the business's confirm button) and
|
|
12
|
+
* is never offered to the model: an instruction planted in an email must not
|
|
13
|
+
* be able to approve an action on the person's behalf.
|
|
14
|
+
*/
|
|
15
|
+
import type { ActionInitiator, ActionOutcome, ContextResult, HarnyClient, SourceArrivalPage, SourceItem } from "../index.js";
|
|
16
|
+
import type { ToolSpec } from "./adapters.js";
|
|
17
|
+
export declare const HARNY_CALLS: readonly ["assembleContext", "act", "undo", "getSourceItem", "listArrivals", "confirm"];
|
|
18
|
+
/** Calls the model can trigger through a tool. `confirm` is deliberately absent. */
|
|
19
|
+
export declare const MODEL_REACHABLE_CALLS: readonly string[];
|
|
20
|
+
/** The client methods the facade needs: a `HarnyClient` built with an app key. */
|
|
21
|
+
export type HarnyClientLike = Pick<HarnyClient, (typeof HARNY_CALLS)[number]>;
|
|
22
|
+
/**
|
|
23
|
+
* Exactly the Harny calls an agent needs, by name, and nothing else. The client
|
|
24
|
+
* (and its key) is held out of sight: logging or serializing the facade shows
|
|
25
|
+
* neither.
|
|
26
|
+
*/
|
|
27
|
+
export declare class HarnyTools {
|
|
28
|
+
constructor(client: HarnyClientLike);
|
|
29
|
+
private get client();
|
|
30
|
+
toJSON(): Record<string, unknown>;
|
|
31
|
+
assembleContext(query: string, options: {
|
|
32
|
+
user: string;
|
|
33
|
+
tokenBudget: number;
|
|
34
|
+
traceparent?: string;
|
|
35
|
+
}): Promise<ContextResult>;
|
|
36
|
+
act(action: string, args: Record<string, unknown>, options: {
|
|
37
|
+
user: string;
|
|
38
|
+
initiatedBy: ActionInitiator;
|
|
39
|
+
idempotencyKey: string;
|
|
40
|
+
correlationId?: string | null;
|
|
41
|
+
traceparent?: string;
|
|
42
|
+
/** The person's own words for this run. */
|
|
43
|
+
endUserMessage?: string | null;
|
|
44
|
+
}): Promise<ActionOutcome>;
|
|
45
|
+
undo(recordId: string, options: {
|
|
46
|
+
user: string;
|
|
47
|
+
initiatedBy: ActionInitiator;
|
|
48
|
+
idempotencyKey: string;
|
|
49
|
+
traceparent?: string;
|
|
50
|
+
}): Promise<ActionOutcome>;
|
|
51
|
+
getSourceItem(itemRef: string, options: {
|
|
52
|
+
user: string;
|
|
53
|
+
traceparent?: string;
|
|
54
|
+
}): Promise<SourceItem>;
|
|
55
|
+
listArrivals(options: {
|
|
56
|
+
user: string;
|
|
57
|
+
after?: number;
|
|
58
|
+
limit?: number;
|
|
59
|
+
traceparent?: string;
|
|
60
|
+
}): Promise<SourceArrivalPage>;
|
|
61
|
+
/** Host-only: the end user's decision from the business's confirm UI. */
|
|
62
|
+
confirm(executionId: string, confirmRef: string, options: {
|
|
63
|
+
approve: boolean;
|
|
64
|
+
user: string;
|
|
65
|
+
traceparent?: string;
|
|
66
|
+
}): Promise<ActionOutcome>;
|
|
67
|
+
}
|
|
68
|
+
export declare const CONTEXT_TOOL = "assemble_context";
|
|
69
|
+
export declare const UNDO_TOOL = "undo_action";
|
|
70
|
+
export declare const GET_ITEM_TOOL = "get_source_item";
|
|
71
|
+
export declare const LIST_ARRIVALS_TOOL = "list_arrivals";
|
|
72
|
+
/**
|
|
73
|
+
* Catalog actions with a precise argument schema. An action missing here still
|
|
74
|
+
* works: it is offered with a free-form arguments object and Harny validates it.
|
|
75
|
+
*/
|
|
76
|
+
export declare const ACTION_TOOL_SPECS: Readonly<Record<string, readonly [string, Record<string, unknown>]>>;
|
|
77
|
+
export declare function actionToolName(action: string): string;
|
|
78
|
+
export declare function buildToolSpecs(actions: readonly string[], options: {
|
|
79
|
+
allowUndo: boolean;
|
|
80
|
+
offerSourceTools: boolean;
|
|
81
|
+
}): ToolSpec[];
|
|
82
|
+
/** A tool result as the model reads it (the same bytes the Python SDK writes). */
|
|
83
|
+
export declare function toolResultJson(payload: Record<string, unknown>): string;
|