@dudousxd/nestjs-agent-core 0.36.0 → 0.38.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.
- package/dist/ag-ui/index.cjs.map +1 -1
- package/dist/ag-ui/index.js.map +1 -1
- package/dist/index.cjs +581 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +395 -1
- package/dist/index.d.ts +395 -1
- package/dist/index.js +566 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -25,6 +25,7 @@ __export(src_exports, {
|
|
|
25
25
|
AGENT_ACTOR_RESOLVER: () => AGENT_ACTOR_RESOLVER,
|
|
26
26
|
AGENT_APPROVAL_PORT: () => AGENT_APPROVAL_PORT,
|
|
27
27
|
AGENT_ATTACHMENT_STAGING: () => AGENT_ATTACHMENT_STAGING,
|
|
28
|
+
AGENT_CONFIRM_TOKEN_STORE: () => AGENT_CONFIRM_TOKEN_STORE,
|
|
28
29
|
AGENT_DEPS_FACTORY: () => AGENT_DEPS_FACTORY,
|
|
29
30
|
AGENT_DIAGNOSTIC_EVENTS: () => AGENT_DIAGNOSTIC_EVENTS,
|
|
30
31
|
AGENT_DURABLE_RUNNER: () => AGENT_DURABLE_RUNNER,
|
|
@@ -54,7 +55,10 @@ __export(src_exports, {
|
|
|
54
55
|
ASK_TOOL_NAME: () => ASK_TOOL_NAME,
|
|
55
56
|
AgentRegistry: () => AgentRegistry,
|
|
56
57
|
AgentStreamError: () => AgentStreamError,
|
|
58
|
+
CONFIRM_JSON_SCHEMA_PROPERTIES: () => CONFIRM_JSON_SCHEMA_PROPERTIES,
|
|
57
59
|
ClosedRolesPolicy: () => ClosedRolesPolicy,
|
|
60
|
+
ConfirmTokenError: () => ConfirmTokenError,
|
|
61
|
+
DEFAULT_CONFIRM_TTL_MS: () => DEFAULT_CONFIRM_TTL_MS,
|
|
58
62
|
DEFAULT_HISTORY_SUMMARY_INSTRUCTION: () => DEFAULT_HISTORY_SUMMARY_INSTRUCTION,
|
|
59
63
|
DEFAULT_INCREMENTAL_LOOKBACK_CHARS: () => DEFAULT_INCREMENTAL_LOOKBACK_CHARS,
|
|
60
64
|
DEFAULT_INTAKE_PREAMBLE: () => DEFAULT_INTAKE_PREAMBLE,
|
|
@@ -70,6 +74,7 @@ __export(src_exports, {
|
|
|
70
74
|
ELICITATION_INPUT_TYPES: () => ELICITATION_INPUT_TYPES,
|
|
71
75
|
GLOBAL_SCOPE: () => GLOBAL_SCOPE,
|
|
72
76
|
InMemoryAgentStore: () => InMemoryAgentStore,
|
|
77
|
+
InMemoryConfirmTokenStore: () => InMemoryConfirmTokenStore,
|
|
73
78
|
MAX_ASK_QUESTIONS: () => MAX_ASK_QUESTIONS,
|
|
74
79
|
OutputRejectedError: () => OutputRejectedError,
|
|
75
80
|
ProcessorFailedError: () => ProcessorFailedError,
|
|
@@ -83,8 +88,10 @@ __export(src_exports, {
|
|
|
83
88
|
RUN_NOT_ACTIVE_MESSAGE: () => RUN_NOT_ACTIVE_MESSAGE,
|
|
84
89
|
RUN_NO_LONGER_RUNNING: () => RUN_NO_LONGER_RUNNING,
|
|
85
90
|
RunCancelledError: () => RunCancelledError,
|
|
91
|
+
SCHEMA_EXTENSION: () => SCHEMA_EXTENSION,
|
|
86
92
|
SKILL_TOOL_DESCRIPTION: () => SKILL_TOOL_DESCRIPTION,
|
|
87
93
|
SKILL_TOOL_NAME: () => SKILL_TOOL_NAME,
|
|
94
|
+
SqlTokenStreamSink: () => SqlTokenStreamSink,
|
|
88
95
|
StructuredOutputError: () => StructuredOutputError,
|
|
89
96
|
THREAD_DETAIL_CONTENT_CHARS: () => THREAD_DETAIL_CONTENT_CHARS,
|
|
90
97
|
ToolDisabledError: () => ToolDisabledError,
|
|
@@ -105,8 +112,10 @@ __export(src_exports, {
|
|
|
105
112
|
buildMemoryBlock: () => buildMemoryBlock,
|
|
106
113
|
buildSkillsBlock: () => buildSkillsBlock,
|
|
107
114
|
canActorUseTool: () => canActorUseTool,
|
|
115
|
+
canonicalJson: () => canonicalJson,
|
|
108
116
|
closeEmptyRoles: () => closeEmptyRoles,
|
|
109
117
|
compositeSkillProvider: () => compositeSkillProvider,
|
|
118
|
+
confirmTokenExpiry: () => confirmTokenExpiry,
|
|
110
119
|
createFrameBuffer: () => createFrameBuffer,
|
|
111
120
|
createIncrementalGate: () => createIncrementalGate,
|
|
112
121
|
createNoopEmitUi: () => createNoopEmitUi,
|
|
@@ -116,6 +125,7 @@ __export(src_exports, {
|
|
|
116
125
|
decodeStreamEvent: () => decodeStreamEvent,
|
|
117
126
|
defaultCanDecide: () => defaultCanDecide,
|
|
118
127
|
defaultScopeResolver: () => defaultScopeResolver,
|
|
128
|
+
defineConfirmedTool: () => defineConfirmedTool,
|
|
119
129
|
detachedDelivered: () => detachedDelivered,
|
|
120
130
|
detachedStarted: () => detachedStarted,
|
|
121
131
|
detachedUnsettled: () => detachedUnsettled,
|
|
@@ -132,6 +142,7 @@ __export(src_exports, {
|
|
|
132
142
|
findCatalogModel: () => findCatalogModel,
|
|
133
143
|
gateFollowUps: () => gateFollowUps,
|
|
134
144
|
gateTail: () => gateTail,
|
|
145
|
+
hashConfirmToken: () => hashConfirmToken,
|
|
135
146
|
invokeWithTransientRetry: () => invokeWithTransientRetry,
|
|
136
147
|
isChatQueueStore: () => isChatQueueStore,
|
|
137
148
|
isControlFlowSignal: () => isControlFlowSignal,
|
|
@@ -184,12 +195,14 @@ __export(src_exports, {
|
|
|
184
195
|
runAgentLoop: () => runAgentLoop,
|
|
185
196
|
runInputProcessors: () => runInputProcessors,
|
|
186
197
|
runOutputProcessors: () => runOutputProcessors,
|
|
198
|
+
schemaExtensionOf: () => schemaExtensionOf,
|
|
187
199
|
seedModelPrices: () => seedModelPrices,
|
|
188
200
|
settleAll: () => settleAll,
|
|
189
201
|
settleDanglingToolCalls: () => settleDanglingToolCalls,
|
|
190
202
|
settleDeadRun: () => settleDeadRun,
|
|
191
203
|
settleElicitation: () => settleElicitation,
|
|
192
204
|
settleUnsettledDelegation: () => settleUnsettledDelegation,
|
|
205
|
+
signConfirmToken: () => signConfirmToken,
|
|
193
206
|
skillInputSchema: () => skillInputSchema,
|
|
194
207
|
skillToolDefinition: () => skillToolDefinition,
|
|
195
208
|
skillWriteVerdict: () => skillWriteVerdict,
|
|
@@ -208,8 +221,10 @@ __export(src_exports, {
|
|
|
208
221
|
validateElicitationAnswer: () => validateElicitationAnswer,
|
|
209
222
|
validateElicitationValue: () => validateElicitationValue,
|
|
210
223
|
validateStructured: () => validateStructured,
|
|
224
|
+
verifyConfirmToken: () => verifyConfirmToken,
|
|
211
225
|
windowHistory: () => windowHistory,
|
|
212
226
|
withAskTool: () => withAskTool,
|
|
227
|
+
withConfirmFields: () => withConfirmFields,
|
|
213
228
|
withMemoryTool: () => withMemoryTool,
|
|
214
229
|
withSelectedModel: () => withSelectedModel,
|
|
215
230
|
withSkillTool: () => withSkillTool,
|
|
@@ -246,6 +261,7 @@ var AGENT_APPROVAL_PORT = /* @__PURE__ */ Symbol.for("@dudousxd/nestjs-agent:app
|
|
|
246
261
|
var AGENT_SKILLS = /* @__PURE__ */ Symbol.for("@dudousxd/nestjs-agent:skills");
|
|
247
262
|
var AGENT_MEMORY = /* @__PURE__ */ Symbol.for("@dudousxd/nestjs-agent:memory");
|
|
248
263
|
var AGENT_SKILL_SOURCES = /* @__PURE__ */ Symbol.for("@dudousxd/nestjs-agent:skill-sources");
|
|
264
|
+
var AGENT_CONFIRM_TOKEN_STORE = /* @__PURE__ */ Symbol.for("@dudousxd/nestjs-agent:confirm-token-store");
|
|
249
265
|
|
|
250
266
|
// src/spi/model-catalog.ts
|
|
251
267
|
function staticModelCatalog(view) {
|
|
@@ -306,7 +322,7 @@ __name(decodeStreamEvent, "decodeStreamEvent");
|
|
|
306
322
|
|
|
307
323
|
// src/turn-frames.ts
|
|
308
324
|
function observeTurnFrames(writer, now = Date.now) {
|
|
309
|
-
const
|
|
325
|
+
const decoder3 = new TextDecoder();
|
|
310
326
|
let pending = "";
|
|
311
327
|
let reasoning = "";
|
|
312
328
|
let reasoningMs = 0;
|
|
@@ -346,7 +362,7 @@ function observeTurnFrames(writer, now = Date.now) {
|
|
|
346
362
|
}
|
|
347
363
|
__name(observeLine, "observeLine");
|
|
348
364
|
function observe(chunk) {
|
|
349
|
-
pending +=
|
|
365
|
+
pending += decoder3.decode(chunk, {
|
|
350
366
|
stream: true
|
|
351
367
|
});
|
|
352
368
|
let newline = pending.indexOf("\n");
|
|
@@ -6006,12 +6022,561 @@ var InMemoryAgentStore = class {
|
|
|
6006
6022
|
};
|
|
6007
6023
|
}
|
|
6008
6024
|
};
|
|
6025
|
+
|
|
6026
|
+
// src/confirm-token.ts
|
|
6027
|
+
var import_node_crypto2 = require("crypto");
|
|
6028
|
+
var DEFAULT_CONFIRM_TTL_MS = 15 * 60 * 1e3;
|
|
6029
|
+
function canonicalJson(value) {
|
|
6030
|
+
if (value === void 0) return "null";
|
|
6031
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value) ?? "null";
|
|
6032
|
+
if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
|
|
6033
|
+
if (typeof value.toJSON === "function") {
|
|
6034
|
+
return canonicalJson(value.toJSON());
|
|
6035
|
+
}
|
|
6036
|
+
const entries = Object.entries(value).filter(([, entry]) => entry !== void 0).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
|
|
6037
|
+
return `{${entries.map(([key, entry]) => `${JSON.stringify(key)}:${canonicalJson(entry)}`).join(",")}}`;
|
|
6038
|
+
}
|
|
6039
|
+
__name(canonicalJson, "canonicalJson");
|
|
6040
|
+
function signature(subject, expiresAt, secret) {
|
|
6041
|
+
if (secret === "") {
|
|
6042
|
+
throw new Error("confirm token: the secret is empty");
|
|
6043
|
+
}
|
|
6044
|
+
return (0, import_node_crypto2.createHmac)("sha256", secret).update(canonicalJson([
|
|
6045
|
+
"agent-confirm",
|
|
6046
|
+
subject.tool,
|
|
6047
|
+
subject.actorId,
|
|
6048
|
+
subject.tenantRef ?? "",
|
|
6049
|
+
expiresAt,
|
|
6050
|
+
subject.args
|
|
6051
|
+
])).digest("base64url");
|
|
6052
|
+
}
|
|
6053
|
+
__name(signature, "signature");
|
|
6054
|
+
function signConfirmToken(subject, options) {
|
|
6055
|
+
return `${options.expiresAt}.${signature(subject, options.expiresAt, options.secret)}`;
|
|
6056
|
+
}
|
|
6057
|
+
__name(signConfirmToken, "signConfirmToken");
|
|
6058
|
+
function confirmTokenExpiry(token) {
|
|
6059
|
+
const separator = token.indexOf(".");
|
|
6060
|
+
if (separator <= 0) return void 0;
|
|
6061
|
+
const expiresAt = Number(token.slice(0, separator));
|
|
6062
|
+
return Number.isSafeInteger(expiresAt) && expiresAt > 0 ? expiresAt : void 0;
|
|
6063
|
+
}
|
|
6064
|
+
__name(confirmTokenExpiry, "confirmTokenExpiry");
|
|
6065
|
+
function verifyConfirmToken(token, subject, options) {
|
|
6066
|
+
if (typeof token !== "string") return false;
|
|
6067
|
+
const expiresAt = confirmTokenExpiry(token);
|
|
6068
|
+
if (expiresAt === void 0 || expiresAt < (options.now ?? Date.now())) return false;
|
|
6069
|
+
const expected = Buffer.from(signature(subject, expiresAt, options.secret));
|
|
6070
|
+
const given = Buffer.from(token.slice(token.indexOf(".") + 1));
|
|
6071
|
+
return expected.length === given.length && (0, import_node_crypto2.timingSafeEqual)(expected, given);
|
|
6072
|
+
}
|
|
6073
|
+
__name(verifyConfirmToken, "verifyConfirmToken");
|
|
6074
|
+
function hashConfirmToken(token) {
|
|
6075
|
+
return (0, import_node_crypto2.createHash)("sha256").update(token).digest("hex");
|
|
6076
|
+
}
|
|
6077
|
+
__name(hashConfirmToken, "hashConfirmToken");
|
|
6078
|
+
var InMemoryConfirmTokenStore = class {
|
|
6079
|
+
static {
|
|
6080
|
+
__name(this, "InMemoryConfirmTokenStore");
|
|
6081
|
+
}
|
|
6082
|
+
claims = /* @__PURE__ */ new Map();
|
|
6083
|
+
async claim(input) {
|
|
6084
|
+
await this.purgeExpired();
|
|
6085
|
+
if (this.claims.has(input.hash)) return false;
|
|
6086
|
+
this.claims.set(input.hash, {
|
|
6087
|
+
...input
|
|
6088
|
+
});
|
|
6089
|
+
return true;
|
|
6090
|
+
}
|
|
6091
|
+
async release(hash) {
|
|
6092
|
+
this.claims.delete(hash);
|
|
6093
|
+
}
|
|
6094
|
+
async purgeExpired(now = Date.now()) {
|
|
6095
|
+
let purged = 0;
|
|
6096
|
+
for (const [hash, claim] of this.claims) {
|
|
6097
|
+
if (claim.expiresAt < now) {
|
|
6098
|
+
this.claims.delete(hash);
|
|
6099
|
+
purged += 1;
|
|
6100
|
+
}
|
|
6101
|
+
}
|
|
6102
|
+
return purged;
|
|
6103
|
+
}
|
|
6104
|
+
/** How many tokens are currently marked as spent. */
|
|
6105
|
+
get size() {
|
|
6106
|
+
return this.claims.size;
|
|
6107
|
+
}
|
|
6108
|
+
};
|
|
6109
|
+
|
|
6110
|
+
// src/confirmed-tool.ts
|
|
6111
|
+
var DEFAULT_MESSAGES = {
|
|
6112
|
+
confirm: 'Nothing was written. Show this preview to the user and ask them to confirm. To commit, call this tool again with the SAME arguments plus "confirm": true and this "confirmToken" (valid for {minutes} minutes).',
|
|
6113
|
+
invalid: 'Invalid or expired confirmation: nothing was written. Call the tool without "confirm" to get a fresh preview, then confirm with the "confirmToken" it returns, without changing the arguments.',
|
|
6114
|
+
used: "This preview was already confirmed: nothing was written again. To repeat the operation, ask for a new preview."
|
|
6115
|
+
};
|
|
6116
|
+
var ConfirmTokenError = class extends Error {
|
|
6117
|
+
static {
|
|
6118
|
+
__name(this, "ConfirmTokenError");
|
|
6119
|
+
}
|
|
6120
|
+
reason;
|
|
6121
|
+
constructor(reason, message) {
|
|
6122
|
+
super(message), this.reason = reason;
|
|
6123
|
+
this.name = "ConfirmTokenError";
|
|
6124
|
+
}
|
|
6125
|
+
};
|
|
6126
|
+
var CONFIRM_JSON_SCHEMA_PROPERTIES = {
|
|
6127
|
+
confirm: {
|
|
6128
|
+
type: "boolean",
|
|
6129
|
+
description: "Omit to get a preview (nothing is written). Send true, with confirmToken, to commit."
|
|
6130
|
+
},
|
|
6131
|
+
confirmToken: {
|
|
6132
|
+
type: "string",
|
|
6133
|
+
description: "The confirmToken the preview returned. Required when confirm is true."
|
|
6134
|
+
}
|
|
6135
|
+
};
|
|
6136
|
+
var SCHEMA_EXTENSION = /* @__PURE__ */ Symbol.for("@dudousxd/nestjs-agent:schema-extension");
|
|
6137
|
+
function schemaExtensionOf(schema) {
|
|
6138
|
+
const extension = schema[SCHEMA_EXTENSION];
|
|
6139
|
+
return typeof extension === "object" && extension !== null ? extension : void 0;
|
|
6140
|
+
}
|
|
6141
|
+
__name(schemaExtensionOf, "schemaExtensionOf");
|
|
6142
|
+
function isRecord(value) {
|
|
6143
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6144
|
+
}
|
|
6145
|
+
__name(isRecord, "isRecord");
|
|
6146
|
+
function splitConfirm(input) {
|
|
6147
|
+
if (!isRecord(input)) return {
|
|
6148
|
+
args: input,
|
|
6149
|
+
fields: {}
|
|
6150
|
+
};
|
|
6151
|
+
const { confirm, confirmToken, ...args } = input;
|
|
6152
|
+
return {
|
|
6153
|
+
args,
|
|
6154
|
+
fields: {
|
|
6155
|
+
...typeof confirm === "boolean" ? {
|
|
6156
|
+
confirm
|
|
6157
|
+
} : {},
|
|
6158
|
+
...typeof confirmToken === "string" ? {
|
|
6159
|
+
confirmToken
|
|
6160
|
+
} : {}
|
|
6161
|
+
}
|
|
6162
|
+
};
|
|
6163
|
+
}
|
|
6164
|
+
__name(splitConfirm, "splitConfirm");
|
|
6165
|
+
function jsonSchemaInputOf(schema) {
|
|
6166
|
+
const standard = schema["~standard"];
|
|
6167
|
+
const input = standard.jsonSchema?.input;
|
|
6168
|
+
return typeof input === "function" ? (options) => input.call(standard.jsonSchema, options) : void 0;
|
|
6169
|
+
}
|
|
6170
|
+
__name(jsonSchemaInputOf, "jsonSchemaInputOf");
|
|
6171
|
+
function withConfirmFields(schema) {
|
|
6172
|
+
const inner = schema["~standard"];
|
|
6173
|
+
const innerJsonSchema = jsonSchemaInputOf(schema);
|
|
6174
|
+
const describe = /* @__PURE__ */ __name((options) => {
|
|
6175
|
+
const base = innerJsonSchema?.(options) ?? {
|
|
6176
|
+
additionalProperties: true
|
|
6177
|
+
};
|
|
6178
|
+
return {
|
|
6179
|
+
...base,
|
|
6180
|
+
type: "object",
|
|
6181
|
+
properties: {
|
|
6182
|
+
...isRecord(base.properties) ? base.properties : {},
|
|
6183
|
+
...CONFIRM_JSON_SCHEMA_PROPERTIES
|
|
6184
|
+
}
|
|
6185
|
+
};
|
|
6186
|
+
}, "describe");
|
|
6187
|
+
const wrapped = {
|
|
6188
|
+
[SCHEMA_EXTENSION]: {
|
|
6189
|
+
base: schema,
|
|
6190
|
+
properties: CONFIRM_JSON_SCHEMA_PROPERTIES
|
|
6191
|
+
},
|
|
6192
|
+
"~standard": {
|
|
6193
|
+
version: 1,
|
|
6194
|
+
vendor: "@dudousxd/nestjs-agent",
|
|
6195
|
+
validate: /* @__PURE__ */ __name(async (value) => {
|
|
6196
|
+
if (!isRecord(value)) {
|
|
6197
|
+
return {
|
|
6198
|
+
issues: [
|
|
6199
|
+
{
|
|
6200
|
+
message: "expected an object"
|
|
6201
|
+
}
|
|
6202
|
+
]
|
|
6203
|
+
};
|
|
6204
|
+
}
|
|
6205
|
+
const issues = [];
|
|
6206
|
+
if (value.confirm != null && typeof value.confirm !== "boolean") {
|
|
6207
|
+
issues.push({
|
|
6208
|
+
message: "expected a boolean",
|
|
6209
|
+
path: [
|
|
6210
|
+
"confirm"
|
|
6211
|
+
]
|
|
6212
|
+
});
|
|
6213
|
+
}
|
|
6214
|
+
if (value.confirmToken != null && typeof value.confirmToken !== "string") {
|
|
6215
|
+
issues.push({
|
|
6216
|
+
message: "expected a string",
|
|
6217
|
+
path: [
|
|
6218
|
+
"confirmToken"
|
|
6219
|
+
]
|
|
6220
|
+
});
|
|
6221
|
+
}
|
|
6222
|
+
const { args, fields } = splitConfirm(value);
|
|
6223
|
+
const result = await inner.validate(args);
|
|
6224
|
+
if (result.issues !== void 0) {
|
|
6225
|
+
return {
|
|
6226
|
+
issues: [
|
|
6227
|
+
...issues,
|
|
6228
|
+
...result.issues
|
|
6229
|
+
]
|
|
6230
|
+
};
|
|
6231
|
+
}
|
|
6232
|
+
if (issues.length > 0) {
|
|
6233
|
+
return {
|
|
6234
|
+
issues
|
|
6235
|
+
};
|
|
6236
|
+
}
|
|
6237
|
+
return {
|
|
6238
|
+
value: isRecord(result.value) ? {
|
|
6239
|
+
...result.value,
|
|
6240
|
+
...fields
|
|
6241
|
+
} : result.value
|
|
6242
|
+
};
|
|
6243
|
+
}, "validate"),
|
|
6244
|
+
jsonSchema: {
|
|
6245
|
+
input: describe,
|
|
6246
|
+
output: describe
|
|
6247
|
+
}
|
|
6248
|
+
}
|
|
6249
|
+
};
|
|
6250
|
+
return wrapped;
|
|
6251
|
+
}
|
|
6252
|
+
__name(withConfirmFields, "withConfirmFields");
|
|
6253
|
+
function defineConfirmedTool(options, steps) {
|
|
6254
|
+
const { secret, ttlMs = DEFAULT_CONFIRM_TTL_MS, store, messages, input, ...specFields } = options;
|
|
6255
|
+
const text = {
|
|
6256
|
+
...DEFAULT_MESSAGES,
|
|
6257
|
+
...messages
|
|
6258
|
+
};
|
|
6259
|
+
const howToConfirm = text.confirm.replaceAll("{minutes}", String(Math.round(ttlMs / 6e4)));
|
|
6260
|
+
const secretNow = /* @__PURE__ */ __name(() => typeof secret === "function" ? secret() : secret, "secretNow");
|
|
6261
|
+
const handler = {
|
|
6262
|
+
async execute(value, ctx) {
|
|
6263
|
+
const { args, fields } = splitConfirm(value);
|
|
6264
|
+
const subject = {
|
|
6265
|
+
tool: options.name,
|
|
6266
|
+
actorId: ctx.actor.id,
|
|
6267
|
+
...ctx.actor.tenantRef !== void 0 ? {
|
|
6268
|
+
tenantRef: ctx.actor.tenantRef
|
|
6269
|
+
} : {},
|
|
6270
|
+
args
|
|
6271
|
+
};
|
|
6272
|
+
const confirming = fields.confirm === true;
|
|
6273
|
+
const token = fields.confirmToken;
|
|
6274
|
+
if (confirming && !verifyConfirmToken(token, subject, {
|
|
6275
|
+
secret: secretNow()
|
|
6276
|
+
})) {
|
|
6277
|
+
throw new ConfirmTokenError("invalid", text.invalid);
|
|
6278
|
+
}
|
|
6279
|
+
const prepared = await steps.prepare(args, ctx);
|
|
6280
|
+
if (!confirming || token === void 0) {
|
|
6281
|
+
const preview = await steps.preview(prepared, ctx);
|
|
6282
|
+
const expiresAt = Date.now() + ttlMs;
|
|
6283
|
+
return {
|
|
6284
|
+
status: "preview",
|
|
6285
|
+
summary: preview.summary,
|
|
6286
|
+
...preview.data !== void 0 ? {
|
|
6287
|
+
data: preview.data
|
|
6288
|
+
} : {},
|
|
6289
|
+
confirmToken: signConfirmToken(subject, {
|
|
6290
|
+
secret: secretNow(),
|
|
6291
|
+
expiresAt
|
|
6292
|
+
}),
|
|
6293
|
+
expiresAt: new Date(expiresAt).toISOString(),
|
|
6294
|
+
confirm: howToConfirm
|
|
6295
|
+
};
|
|
6296
|
+
}
|
|
6297
|
+
const hash = hashConfirmToken(token);
|
|
6298
|
+
if (store !== void 0) {
|
|
6299
|
+
const claimed = await store.claim({
|
|
6300
|
+
hash,
|
|
6301
|
+
actorRef: ctx.actor.id,
|
|
6302
|
+
tool: options.name,
|
|
6303
|
+
expiresAt: confirmTokenExpiry(token) ?? Date.now() + ttlMs
|
|
6304
|
+
});
|
|
6305
|
+
if (!claimed) {
|
|
6306
|
+
throw new ConfirmTokenError("used", text.used);
|
|
6307
|
+
}
|
|
6308
|
+
}
|
|
6309
|
+
try {
|
|
6310
|
+
const done = await steps.commit(prepared, ctx);
|
|
6311
|
+
return {
|
|
6312
|
+
status: "done",
|
|
6313
|
+
summary: done.summary,
|
|
6314
|
+
...done.data !== void 0 ? {
|
|
6315
|
+
data: done.data
|
|
6316
|
+
} : {}
|
|
6317
|
+
};
|
|
6318
|
+
} catch (error) {
|
|
6319
|
+
await store?.release(hash).catch(() => void 0);
|
|
6320
|
+
throw error;
|
|
6321
|
+
}
|
|
6322
|
+
}
|
|
6323
|
+
};
|
|
6324
|
+
return {
|
|
6325
|
+
spec: {
|
|
6326
|
+
...specFields,
|
|
6327
|
+
kind: "read",
|
|
6328
|
+
inputSchema: withConfirmFields(input)
|
|
6329
|
+
},
|
|
6330
|
+
handler
|
|
6331
|
+
};
|
|
6332
|
+
}
|
|
6333
|
+
__name(defineConfirmedTool, "defineConfirmedTool");
|
|
6334
|
+
|
|
6335
|
+
// src/sql-token-stream-sink.ts
|
|
6336
|
+
var DEFAULT_TTL_SECONDS = 3600;
|
|
6337
|
+
var DEFAULT_POLL_INTERVAL_MS = 250;
|
|
6338
|
+
var DEFAULT_IDLE_POLL_INTERVAL_MS = 1e3;
|
|
6339
|
+
var IDLE_AFTER_MS = 5e3;
|
|
6340
|
+
var DEFAULT_FLUSH_MS = 50;
|
|
6341
|
+
var READ_PAGE = 500;
|
|
6342
|
+
var PURGE_CHUNK = 200;
|
|
6343
|
+
var AUTO_PURGE_EVERY_MS = 6e4;
|
|
6344
|
+
var APPEND_ATTEMPTS = 8;
|
|
6345
|
+
var decoder2 = new TextDecoder();
|
|
6346
|
+
var encoder2 = new TextEncoder();
|
|
6347
|
+
var sleep = /* @__PURE__ */ __name((ms) => new Promise((resolve) => setTimeout(resolve, ms)), "sleep");
|
|
6348
|
+
function textOf(line) {
|
|
6349
|
+
if (!line.startsWith('{"kind":"text"')) return null;
|
|
6350
|
+
try {
|
|
6351
|
+
const parsed = JSON.parse(line);
|
|
6352
|
+
if (typeof parsed === "object" && parsed !== null && Object.keys(parsed).length === 2 && parsed.kind === "text" && typeof parsed.text === "string") {
|
|
6353
|
+
return parsed.text;
|
|
6354
|
+
}
|
|
6355
|
+
} catch {
|
|
6356
|
+
}
|
|
6357
|
+
return null;
|
|
6358
|
+
}
|
|
6359
|
+
__name(textOf, "textOf");
|
|
6360
|
+
var SqlTokenStreamSink = class {
|
|
6361
|
+
static {
|
|
6362
|
+
__name(this, "SqlTokenStreamSink");
|
|
6363
|
+
}
|
|
6364
|
+
table;
|
|
6365
|
+
pollIntervalMs;
|
|
6366
|
+
idlePollIntervalMs;
|
|
6367
|
+
flushMs;
|
|
6368
|
+
ttlSeconds;
|
|
6369
|
+
autoPurge;
|
|
6370
|
+
writes = /* @__PURE__ */ new Map();
|
|
6371
|
+
lastAutoPurge = 0;
|
|
6372
|
+
constructor(table, options = {}) {
|
|
6373
|
+
this.table = table;
|
|
6374
|
+
this.pollIntervalMs = Math.max(1, options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS);
|
|
6375
|
+
this.idlePollIntervalMs = Math.max(this.pollIntervalMs, options.idlePollIntervalMs ?? DEFAULT_IDLE_POLL_INTERVAL_MS);
|
|
6376
|
+
this.flushMs = Math.max(0, options.flushMs ?? DEFAULT_FLUSH_MS);
|
|
6377
|
+
this.ttlSeconds = options.ttlSeconds ?? DEFAULT_TTL_SECONDS;
|
|
6378
|
+
this.autoPurge = options.autoPurge ?? true;
|
|
6379
|
+
}
|
|
6380
|
+
runWrites(runId) {
|
|
6381
|
+
let state = this.writes.get(runId);
|
|
6382
|
+
if (state === void 0) {
|
|
6383
|
+
state = {
|
|
6384
|
+
text: null,
|
|
6385
|
+
timer: void 0,
|
|
6386
|
+
tail: Promise.resolve(),
|
|
6387
|
+
pending: 0,
|
|
6388
|
+
failure: void 0
|
|
6389
|
+
};
|
|
6390
|
+
this.writes.set(runId, state);
|
|
6391
|
+
}
|
|
6392
|
+
return state;
|
|
6393
|
+
}
|
|
6394
|
+
/** Forget a run's write state once nothing is gathered, queued or left to report. */
|
|
6395
|
+
release(runId, state) {
|
|
6396
|
+
if (state.pending === 0 && state.text === null && state.failure === void 0 && this.writes.get(runId) === state) {
|
|
6397
|
+
this.writes.delete(runId);
|
|
6398
|
+
}
|
|
6399
|
+
}
|
|
6400
|
+
/** Queue `work` behind every write already queued for the run, so rows land in call order. */
|
|
6401
|
+
enqueue(runId, state, work) {
|
|
6402
|
+
state.pending += 1;
|
|
6403
|
+
const next = state.tail.then(work);
|
|
6404
|
+
state.tail = next.then(() => void 0, () => void 0).then(() => {
|
|
6405
|
+
state.pending -= 1;
|
|
6406
|
+
this.release(runId, state);
|
|
6407
|
+
});
|
|
6408
|
+
return next;
|
|
6409
|
+
}
|
|
6410
|
+
/** Queue the gathered text (if any) as one `text` row. */
|
|
6411
|
+
flushText(runId, state) {
|
|
6412
|
+
if (state.timer !== void 0) {
|
|
6413
|
+
clearTimeout(state.timer);
|
|
6414
|
+
state.timer = void 0;
|
|
6415
|
+
}
|
|
6416
|
+
if (state.text === null) return Promise.resolve();
|
|
6417
|
+
const line = decoder2.decode(encodeStreamEvent({
|
|
6418
|
+
kind: "text",
|
|
6419
|
+
text: state.text
|
|
6420
|
+
}));
|
|
6421
|
+
state.text = null;
|
|
6422
|
+
return this.enqueue(runId, state, () => this.append(runId, line, null));
|
|
6423
|
+
}
|
|
6424
|
+
/** Raise, once, a gathered write that failed with nobody awaiting it. */
|
|
6425
|
+
raiseFailure(state) {
|
|
6426
|
+
const failure = state.failure;
|
|
6427
|
+
if (failure !== void 0) {
|
|
6428
|
+
state.failure = void 0;
|
|
6429
|
+
throw failure.error;
|
|
6430
|
+
}
|
|
6431
|
+
}
|
|
6432
|
+
/** Append one row — a frame, or the terminal row (`frame: null`, with `error` on a failure). */
|
|
6433
|
+
async append(runId, frame, error) {
|
|
6434
|
+
for (let attempt = 1; ; attempt += 1) {
|
|
6435
|
+
try {
|
|
6436
|
+
await this.table.append(runId, {
|
|
6437
|
+
frame,
|
|
6438
|
+
error,
|
|
6439
|
+
createdAt: Date.now()
|
|
6440
|
+
});
|
|
6441
|
+
return;
|
|
6442
|
+
} catch (caught) {
|
|
6443
|
+
if (attempt >= APPEND_ATTEMPTS || !this.table.isUniqueViolation(caught)) throw caught;
|
|
6444
|
+
}
|
|
6445
|
+
}
|
|
6446
|
+
}
|
|
6447
|
+
/** Write out what is gathered, then a terminal row; raise a failure nobody saw. */
|
|
6448
|
+
async terminate(runId, error) {
|
|
6449
|
+
const state = this.runWrites(runId);
|
|
6450
|
+
const flushed = this.flushText(runId, state);
|
|
6451
|
+
const ended = this.enqueue(runId, state, () => this.append(runId, null, error));
|
|
6452
|
+
await Promise.all([
|
|
6453
|
+
flushed,
|
|
6454
|
+
ended
|
|
6455
|
+
]);
|
|
6456
|
+
this.raiseFailure(state);
|
|
6457
|
+
this.release(runId, state);
|
|
6458
|
+
this.purgeInBackground();
|
|
6459
|
+
}
|
|
6460
|
+
/**
|
|
6461
|
+
* The run's writer. Writers opened for the same run in one process share what they are gathering,
|
|
6462
|
+
* so a delegated run's text (forwarded through a child writer) and its parent's next frame keep
|
|
6463
|
+
* the order they were written in.
|
|
6464
|
+
*/
|
|
6465
|
+
open(runId) {
|
|
6466
|
+
return {
|
|
6467
|
+
write: /* @__PURE__ */ __name(async (chunk) => {
|
|
6468
|
+
const state = this.runWrites(runId);
|
|
6469
|
+
this.raiseFailure(state);
|
|
6470
|
+
const line = decoder2.decode(chunk);
|
|
6471
|
+
const text = this.flushMs > 0 ? textOf(line.trimEnd()) : null;
|
|
6472
|
+
if (text !== null) {
|
|
6473
|
+
state.text = (state.text ?? "") + text;
|
|
6474
|
+
if (state.timer === void 0) {
|
|
6475
|
+
state.timer = setTimeout(() => {
|
|
6476
|
+
state.timer = void 0;
|
|
6477
|
+
this.flushText(runId, state).catch((error) => {
|
|
6478
|
+
state.failure = {
|
|
6479
|
+
error
|
|
6480
|
+
};
|
|
6481
|
+
});
|
|
6482
|
+
}, this.flushMs);
|
|
6483
|
+
}
|
|
6484
|
+
return;
|
|
6485
|
+
}
|
|
6486
|
+
const flushed = this.flushText(runId, state);
|
|
6487
|
+
const appended = this.enqueue(runId, state, () => this.append(runId, line, null));
|
|
6488
|
+
await Promise.all([
|
|
6489
|
+
flushed,
|
|
6490
|
+
appended
|
|
6491
|
+
]);
|
|
6492
|
+
}, "write"),
|
|
6493
|
+
flush: /* @__PURE__ */ __name(async () => {
|
|
6494
|
+
const state = this.runWrites(runId);
|
|
6495
|
+
const flushed = this.flushText(runId, state);
|
|
6496
|
+
await Promise.all([
|
|
6497
|
+
flushed,
|
|
6498
|
+
state.tail
|
|
6499
|
+
]);
|
|
6500
|
+
this.raiseFailure(state);
|
|
6501
|
+
this.release(runId, state);
|
|
6502
|
+
}, "flush"),
|
|
6503
|
+
end: /* @__PURE__ */ __name(() => this.terminate(runId, null), "end"),
|
|
6504
|
+
fail: /* @__PURE__ */ __name((error) => this.terminate(runId, JSON.stringify({
|
|
6505
|
+
code: error.code,
|
|
6506
|
+
message: error.message
|
|
6507
|
+
})), "fail")
|
|
6508
|
+
};
|
|
6509
|
+
}
|
|
6510
|
+
async *subscribe(runId) {
|
|
6511
|
+
let cursor = 0;
|
|
6512
|
+
let quietSince = Date.now();
|
|
6513
|
+
while (true) {
|
|
6514
|
+
const rows = await this.table.read(runId, cursor, READ_PAGE);
|
|
6515
|
+
for (const row of rows) {
|
|
6516
|
+
cursor = row.seq;
|
|
6517
|
+
if (row.frame === null) {
|
|
6518
|
+
if (row.error !== null) {
|
|
6519
|
+
throw new AgentStreamError(JSON.parse(row.error));
|
|
6520
|
+
}
|
|
6521
|
+
return;
|
|
6522
|
+
}
|
|
6523
|
+
yield encoder2.encode(row.frame);
|
|
6524
|
+
}
|
|
6525
|
+
if (rows.length > 0) {
|
|
6526
|
+
quietSince = Date.now();
|
|
6527
|
+
if (rows.length >= READ_PAGE) continue;
|
|
6528
|
+
}
|
|
6529
|
+
await sleep(Date.now() - quietSince >= IDLE_AFTER_MS ? this.idlePollIntervalMs : this.pollIntervalMs);
|
|
6530
|
+
}
|
|
6531
|
+
}
|
|
6532
|
+
/** Does the table hold anything for the run — a frame, or its end? */
|
|
6533
|
+
has(runId) {
|
|
6534
|
+
return this.table.has(runId);
|
|
6535
|
+
}
|
|
6536
|
+
async close(runId) {
|
|
6537
|
+
const state = this.writes.get(runId);
|
|
6538
|
+
if (state !== void 0) {
|
|
6539
|
+
if (state.timer !== void 0) clearTimeout(state.timer);
|
|
6540
|
+
state.timer = void 0;
|
|
6541
|
+
state.text = null;
|
|
6542
|
+
state.failure = void 0;
|
|
6543
|
+
await state.tail;
|
|
6544
|
+
this.writes.delete(runId);
|
|
6545
|
+
}
|
|
6546
|
+
await this.table.remove([
|
|
6547
|
+
runId
|
|
6548
|
+
]);
|
|
6549
|
+
}
|
|
6550
|
+
/**
|
|
6551
|
+
* Delete every run whose last write is older than `ttlSeconds` at `now` (epoch-ms) — ended runs
|
|
6552
|
+
* past their replay window and runs that crashed without ending alike. Returns how many runs went.
|
|
6553
|
+
* Safe from any replica, and from several at once. A no-op under `ttlSeconds: 0`.
|
|
6554
|
+
*/
|
|
6555
|
+
async purgeExpired(now = Date.now()) {
|
|
6556
|
+
if (this.ttlSeconds <= 0) return 0;
|
|
6557
|
+
const lapsed = await this.table.lapsedRuns(now - this.ttlSeconds * 1e3);
|
|
6558
|
+
for (let index = 0; index < lapsed.length; index += PURGE_CHUNK) {
|
|
6559
|
+
await this.table.remove(lapsed.slice(index, index + PURGE_CHUNK));
|
|
6560
|
+
}
|
|
6561
|
+
return lapsed.length;
|
|
6562
|
+
}
|
|
6563
|
+
/** {@link purgeExpired}, unawaited and at most once a minute. Its failure is not the run's. */
|
|
6564
|
+
purgeInBackground() {
|
|
6565
|
+
if (!this.autoPurge || this.ttlSeconds <= 0) return;
|
|
6566
|
+
const now = Date.now();
|
|
6567
|
+
if (now - this.lastAutoPurge < AUTO_PURGE_EVERY_MS) return;
|
|
6568
|
+
this.lastAutoPurge = now;
|
|
6569
|
+
this.purgeExpired(now).catch(() => {
|
|
6570
|
+
});
|
|
6571
|
+
}
|
|
6572
|
+
};
|
|
6009
6573
|
// Annotate the CommonJS export names for ESM import in node:
|
|
6010
6574
|
0 && (module.exports = {
|
|
6011
6575
|
AGENT_ACTOR_DIRECTORY,
|
|
6012
6576
|
AGENT_ACTOR_RESOLVER,
|
|
6013
6577
|
AGENT_APPROVAL_PORT,
|
|
6014
6578
|
AGENT_ATTACHMENT_STAGING,
|
|
6579
|
+
AGENT_CONFIRM_TOKEN_STORE,
|
|
6015
6580
|
AGENT_DEPS_FACTORY,
|
|
6016
6581
|
AGENT_DIAGNOSTIC_EVENTS,
|
|
6017
6582
|
AGENT_DURABLE_RUNNER,
|
|
@@ -6041,7 +6606,10 @@ var InMemoryAgentStore = class {
|
|
|
6041
6606
|
ASK_TOOL_NAME,
|
|
6042
6607
|
AgentRegistry,
|
|
6043
6608
|
AgentStreamError,
|
|
6609
|
+
CONFIRM_JSON_SCHEMA_PROPERTIES,
|
|
6044
6610
|
ClosedRolesPolicy,
|
|
6611
|
+
ConfirmTokenError,
|
|
6612
|
+
DEFAULT_CONFIRM_TTL_MS,
|
|
6045
6613
|
DEFAULT_HISTORY_SUMMARY_INSTRUCTION,
|
|
6046
6614
|
DEFAULT_INCREMENTAL_LOOKBACK_CHARS,
|
|
6047
6615
|
DEFAULT_INTAKE_PREAMBLE,
|
|
@@ -6057,6 +6625,7 @@ var InMemoryAgentStore = class {
|
|
|
6057
6625
|
ELICITATION_INPUT_TYPES,
|
|
6058
6626
|
GLOBAL_SCOPE,
|
|
6059
6627
|
InMemoryAgentStore,
|
|
6628
|
+
InMemoryConfirmTokenStore,
|
|
6060
6629
|
MAX_ASK_QUESTIONS,
|
|
6061
6630
|
OutputRejectedError,
|
|
6062
6631
|
ProcessorFailedError,
|
|
@@ -6070,8 +6639,10 @@ var InMemoryAgentStore = class {
|
|
|
6070
6639
|
RUN_NOT_ACTIVE_MESSAGE,
|
|
6071
6640
|
RUN_NO_LONGER_RUNNING,
|
|
6072
6641
|
RunCancelledError,
|
|
6642
|
+
SCHEMA_EXTENSION,
|
|
6073
6643
|
SKILL_TOOL_DESCRIPTION,
|
|
6074
6644
|
SKILL_TOOL_NAME,
|
|
6645
|
+
SqlTokenStreamSink,
|
|
6075
6646
|
StructuredOutputError,
|
|
6076
6647
|
THREAD_DETAIL_CONTENT_CHARS,
|
|
6077
6648
|
ToolDisabledError,
|
|
@@ -6092,8 +6663,10 @@ var InMemoryAgentStore = class {
|
|
|
6092
6663
|
buildMemoryBlock,
|
|
6093
6664
|
buildSkillsBlock,
|
|
6094
6665
|
canActorUseTool,
|
|
6666
|
+
canonicalJson,
|
|
6095
6667
|
closeEmptyRoles,
|
|
6096
6668
|
compositeSkillProvider,
|
|
6669
|
+
confirmTokenExpiry,
|
|
6097
6670
|
createFrameBuffer,
|
|
6098
6671
|
createIncrementalGate,
|
|
6099
6672
|
createNoopEmitUi,
|
|
@@ -6103,6 +6676,7 @@ var InMemoryAgentStore = class {
|
|
|
6103
6676
|
decodeStreamEvent,
|
|
6104
6677
|
defaultCanDecide,
|
|
6105
6678
|
defaultScopeResolver,
|
|
6679
|
+
defineConfirmedTool,
|
|
6106
6680
|
detachedDelivered,
|
|
6107
6681
|
detachedStarted,
|
|
6108
6682
|
detachedUnsettled,
|
|
@@ -6119,6 +6693,7 @@ var InMemoryAgentStore = class {
|
|
|
6119
6693
|
findCatalogModel,
|
|
6120
6694
|
gateFollowUps,
|
|
6121
6695
|
gateTail,
|
|
6696
|
+
hashConfirmToken,
|
|
6122
6697
|
invokeWithTransientRetry,
|
|
6123
6698
|
isChatQueueStore,
|
|
6124
6699
|
isControlFlowSignal,
|
|
@@ -6171,12 +6746,14 @@ var InMemoryAgentStore = class {
|
|
|
6171
6746
|
runAgentLoop,
|
|
6172
6747
|
runInputProcessors,
|
|
6173
6748
|
runOutputProcessors,
|
|
6749
|
+
schemaExtensionOf,
|
|
6174
6750
|
seedModelPrices,
|
|
6175
6751
|
settleAll,
|
|
6176
6752
|
settleDanglingToolCalls,
|
|
6177
6753
|
settleDeadRun,
|
|
6178
6754
|
settleElicitation,
|
|
6179
6755
|
settleUnsettledDelegation,
|
|
6756
|
+
signConfirmToken,
|
|
6180
6757
|
skillInputSchema,
|
|
6181
6758
|
skillToolDefinition,
|
|
6182
6759
|
skillWriteVerdict,
|
|
@@ -6195,8 +6772,10 @@ var InMemoryAgentStore = class {
|
|
|
6195
6772
|
validateElicitationAnswer,
|
|
6196
6773
|
validateElicitationValue,
|
|
6197
6774
|
validateStructured,
|
|
6775
|
+
verifyConfirmToken,
|
|
6198
6776
|
windowHistory,
|
|
6199
6777
|
withAskTool,
|
|
6778
|
+
withConfirmFields,
|
|
6200
6779
|
withMemoryTool,
|
|
6201
6780
|
withSelectedModel,
|
|
6202
6781
|
withSkillTool,
|