@zhin.js/agent 1.1.38 → 1.1.40
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/lib/assistant/job-engine.d.ts +5 -0
- package/lib/assistant/job-engine.js +20 -1
- package/lib/assistant/job-engine.js.map +1 -1
- package/lib/assistant/job-storage.d.ts +238 -0
- package/lib/assistant/job-storage.js +143 -0
- package/lib/assistant/job-storage.js.map +1 -0
- package/lib/assistant/job-store.d.ts +7 -0
- package/lib/assistant/job-store.js +41 -3
- package/lib/assistant/job-store.js.map +1 -1
- package/lib/config/perception-config.d.ts +9 -0
- package/lib/config/perception-config.js +27 -0
- package/lib/config/perception-config.js.map +1 -1
- package/lib/context/context-system.d.ts +1 -0
- package/lib/context/context-system.js +8 -8
- package/lib/context/context-system.js.map +1 -1
- package/lib/context/im-turn-context-adapter.js +2 -0
- package/lib/context/im-turn-context-adapter.js.map +1 -1
- package/lib/context/index.d.ts +1 -1
- package/lib/context/index.js +1 -1
- package/lib/context/index.js.map +1 -1
- package/lib/context/skill-context.d.ts +3 -0
- package/lib/context/skill-context.js +6 -0
- package/lib/context/skill-context.js.map +1 -0
- package/lib/context/turn-envelope.d.ts +7 -1
- package/lib/context/turn-envelope.js +30 -7
- package/lib/context/turn-envelope.js.map +1 -1
- package/lib/context/turn-user-message.d.ts +3 -1
- package/lib/context/turn-user-message.js +14 -1
- package/lib/context/turn-user-message.js.map +1 -1
- package/lib/core/agent-core-run.d.ts +1 -0
- package/lib/core/agent-core-run.js +68 -34
- package/lib/core/agent-core-run.js.map +1 -1
- package/lib/core/structured-reply-recovery.d.ts +13 -0
- package/lib/core/structured-reply-recovery.js +41 -5
- package/lib/core/structured-reply-recovery.js.map +1 -1
- package/lib/core/turn-completion-usage.d.ts +2 -1
- package/lib/core/turn-completion-usage.js +14 -5
- package/lib/core/turn-completion-usage.js.map +1 -1
- package/lib/core/turn-event-mapper.d.ts +1 -1
- package/lib/core/turn-event-mapper.js +8 -5
- package/lib/core/turn-event-mapper.js.map +1 -1
- package/lib/event/turn-event.d.ts +7 -1
- package/lib/event/turn-event.js.map +1 -1
- package/lib/index.d.ts +4 -1
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -1
- package/lib/media/perception.d.ts +3 -4
- package/lib/media/perception.js +59 -37
- package/lib/media/perception.js.map +1 -1
- package/lib/memory/compaction-runtime.d.ts +3 -2
- package/lib/memory/compaction-runtime.js +22 -14
- package/lib/memory/compaction-runtime.js.map +1 -1
- package/lib/outbound/agent-output.js +2 -0
- package/lib/outbound/agent-output.js.map +1 -1
- package/lib/outbound/chat-failure.d.ts +27 -0
- package/lib/outbound/chat-failure.js +53 -0
- package/lib/outbound/chat-failure.js.map +1 -0
- package/lib/outbound/structured-reply.d.ts +7 -0
- package/lib/outbound/structured-reply.js +72 -16
- package/lib/outbound/structured-reply.js.map +1 -1
- package/lib/plugin-runtime/agent-runtime.js +49 -8
- package/lib/plugin-runtime/agent-runtime.js.map +1 -1
- package/lib/plugin-runtime/ai-completion.d.ts +4 -3
- package/lib/plugin-runtime/ai-completion.js +64 -10
- package/lib/plugin-runtime/ai-completion.js.map +1 -1
- package/lib/plugin-runtime/capability-ingress.js +3 -1
- package/lib/plugin-runtime/capability-ingress.js.map +1 -1
- package/lib/plugin-runtime/deferred-capability-plan.d.ts +4 -1
- package/lib/plugin-runtime/deferred-capability-plan.js +25 -9
- package/lib/plugin-runtime/deferred-capability-plan.js.map +1 -1
- package/lib/plugin-runtime/full-agent-turn-engine.js +1 -0
- package/lib/plugin-runtime/full-agent-turn-engine.js.map +1 -1
- package/lib/plugin-runtime/index.d.ts +2 -0
- package/lib/plugin-runtime/index.js +2 -0
- package/lib/plugin-runtime/index.js.map +1 -1
- package/lib/prompt/assembly.js +0 -9
- package/lib/prompt/assembly.js.map +1 -1
- package/lib/prompt/git-context.js +1 -1
- package/lib/prompt/git-context.js.map +1 -1
- package/lib/prompt/rules/chat-rules.js +8 -9
- package/lib/prompt/rules/chat-rules.js.map +1 -1
- package/lib/prompt/rules/critical-rules.js +10 -10
- package/lib/prompt/rules/critical-rules.js.map +1 -1
- package/lib/prompt/system-prompt.js +4 -5
- package/lib/prompt/system-prompt.js.map +1 -1
- package/lib/security/file-role-policy.js +6 -6
- package/lib/security/file-role-policy.js.map +1 -1
- package/lib/security/policy-facade.js +1 -1
- package/lib/security/policy-facade.js.map +1 -1
- package/lib/security/usage-quota.d.ts +4 -0
- package/lib/security/usage-quota.js +23 -2
- package/lib/security/usage-quota.js.map +1 -1
- package/lib/session/approval-port.d.ts +2 -0
- package/lib/session/approval-port.js.map +1 -1
- package/lib/session/approval-review-agent.d.ts +1 -1
- package/lib/session/approval-review-agent.js +19 -4
- package/lib/session/approval-review-agent.js.map +1 -1
- package/lib/session/turn-ingress-session.js +7 -1
- package/lib/session/turn-ingress-session.js.map +1 -1
- package/lib/tool/tool-approval-gate.js +4 -2
- package/lib/tool/tool-approval-gate.js.map +1 -1
- package/lib/tool/turn-tool-runtime.js +24 -5
- package/lib/tool/turn-tool-runtime.js.map +1 -1
- package/lib/tool-catalog/deferred-turn-controller.js +1 -4
- package/lib/tool-catalog/deferred-turn-controller.js.map +1 -1
- package/lib/trace/context-budget.d.ts +4 -3
- package/lib/trace/context-budget.js +28 -8
- package/lib/trace/context-budget.js.map +1 -1
- package/lib/trace/turn-trace-format.js +4 -1
- package/lib/trace/turn-trace-format.js.map +1 -1
- package/lib/trace/turn-trace.d.ts +6 -0
- package/lib/trace/turn-trace.js +8 -2
- package/lib/trace/turn-trace.js.map +1 -1
- package/lib/trace/turn-usage-log.d.ts +14 -0
- package/lib/trace/turn-usage-log.js +83 -0
- package/lib/trace/turn-usage-log.js.map +1 -0
- package/lib/usage/usage-store.d.ts +199 -0
- package/lib/usage/usage-store.js +121 -0
- package/lib/usage/usage-store.js.map +1 -0
- package/package.json +13 -13
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { AgentUsageCollector, agentUsageStoreToken } from '../usage/usage-store.js';
|
|
2
|
+
import { getLogger } from '@zhin.js/logger';
|
|
3
|
+
import { logTurnUsage } from '../trace/turn-usage-log.js';
|
|
1
4
|
import { createToken } from '@zhin.js/plugin-runtime';
|
|
2
5
|
import { applyTurnTrust } from '../security/trust-level.js';
|
|
3
6
|
import { PersistentTurnJournal } from '../journal/persistent-turn-journal.js';
|
|
@@ -163,6 +166,7 @@ export const agentTurnEngineToken = createToken('zhin.agent.turn-engine', 'Compl
|
|
|
163
166
|
export class AgentRuntime extends SnapshotAttachedRuntime {
|
|
164
167
|
options;
|
|
165
168
|
#ingress = new CapabilityIngress();
|
|
169
|
+
#usageLogger = getLogger('ai.usage');
|
|
166
170
|
constructor(options) {
|
|
167
171
|
super();
|
|
168
172
|
this.options = options;
|
|
@@ -190,8 +194,19 @@ export class AgentRuntime extends SnapshotAttachedRuntime {
|
|
|
190
194
|
}
|
|
191
195
|
async #executeLeased(lease, owner, request, selection, observe, admit = () => undefined) {
|
|
192
196
|
let active = true;
|
|
197
|
+
const usageStore = lease.value.resources.get(lease.value.root)?.get(agentUsageStoreToken.id);
|
|
198
|
+
const usage = usageStore ? new AgentUsageCollector(String(owner), request, {
|
|
199
|
+
provider: selection.binding.providerAlias, model: selection.binding.model,
|
|
200
|
+
}) : undefined;
|
|
201
|
+
let usageStatus = 'failed';
|
|
193
202
|
let activeTrace;
|
|
194
203
|
let releaseTrace;
|
|
204
|
+
let outcome;
|
|
205
|
+
const logContext = {
|
|
206
|
+
traceId: request.identity.traceId,
|
|
207
|
+
scene: request.origin.kind === 'im' ? `${request.origin.platform}/${request.origin.scope}` : request.origin.kind,
|
|
208
|
+
selectedModel: `${selection.binding.providerAlias}/${selection.binding.model}`,
|
|
209
|
+
};
|
|
195
210
|
try {
|
|
196
211
|
if (!active)
|
|
197
212
|
throw new Error('Agent generation operation is not active');
|
|
@@ -211,7 +226,7 @@ export class AgentRuntime extends SnapshotAttachedRuntime {
|
|
|
211
226
|
const turnRequest = trust.restricted
|
|
212
227
|
? Object.freeze({ ...request, policy: trust.policy })
|
|
213
228
|
: request;
|
|
214
|
-
const trace = this.options.turnTraceStore
|
|
229
|
+
const trace = this.options.turnTraceStore || this.#usageLogger.isLevelEnabled('info')
|
|
215
230
|
? new TurnTraceCollector({
|
|
216
231
|
turnId: request.identity.turnId,
|
|
217
232
|
sessionKey: request.session.key,
|
|
@@ -220,7 +235,7 @@ export class AgentRuntime extends SnapshotAttachedRuntime {
|
|
|
220
235
|
: undefined;
|
|
221
236
|
releaseTrace = trace ? registerTurnTrace(trace) : undefined;
|
|
222
237
|
activeTrace = trace;
|
|
223
|
-
const turn = createIngressTurn(lease.value, turnRequest, capabilities, trace);
|
|
238
|
+
const turn = createIngressTurn(lease.value, turnRequest, capabilities, trace, usage);
|
|
224
239
|
const catalog = Object.freeze({
|
|
225
240
|
...capabilities,
|
|
226
241
|
tools: Object.freeze(capabilities.tools.map(({ execute: _execute, ...tool }) => Object.freeze(tool))),
|
|
@@ -229,7 +244,7 @@ export class AgentRuntime extends SnapshotAttachedRuntime {
|
|
|
229
244
|
const engine = resolveTurnEngine(lease.value);
|
|
230
245
|
const disabled = Boolean(request.session.key.startsWith('workroom:') || request.input.metadata?.workroom
|
|
231
246
|
|| request.principal.roles.includes('workroom_assignment') || request.execution?.kind === 'schedule');
|
|
232
|
-
|
|
247
|
+
outcome = await runWithAgentDecisionTurn(lease.value, request.identity.turnId, decision => runWithAgentTurnConfiguration({ activeBinding: selection.binding }, () => executeAgentTurn(turn, async function* () {
|
|
233
248
|
const stream = engine.run({
|
|
234
249
|
turn,
|
|
235
250
|
capabilities: catalog,
|
|
@@ -261,18 +276,42 @@ export class AgentRuntime extends SnapshotAttachedRuntime {
|
|
|
261
276
|
await stream.return(undefined);
|
|
262
277
|
}
|
|
263
278
|
}, observe)), { disabled });
|
|
279
|
+
usageStatus = outcome.status;
|
|
280
|
+
return outcome;
|
|
281
|
+
}
|
|
282
|
+
catch (error) {
|
|
283
|
+
usageStatus = request.signal.aborted ? 'cancelled' : 'failed';
|
|
284
|
+
if (!activeTrace && this.#usageLogger.isLevelEnabled('info')) {
|
|
285
|
+
activeTrace = new TurnTraceCollector({ turnId: request.identity.turnId, sessionKey: request.session.key });
|
|
286
|
+
}
|
|
287
|
+
activeTrace?.finalize({ status: request.signal.aborted ? 'cancelled' : 'failed' });
|
|
288
|
+
throw error;
|
|
264
289
|
}
|
|
265
290
|
finally {
|
|
266
291
|
active = false;
|
|
267
292
|
releaseTrace?.();
|
|
268
293
|
if (activeTrace)
|
|
269
|
-
this.#saveTrace(activeTrace);
|
|
294
|
+
this.#saveTrace(activeTrace, { ...logContext, status: outcome?.status });
|
|
295
|
+
if (usage && usageStore) {
|
|
296
|
+
try {
|
|
297
|
+
await usageStore.save(usage.finish(usageStatus));
|
|
298
|
+
}
|
|
299
|
+
catch {
|
|
300
|
+
// No model response, prompt or database error text enters this diagnostic.
|
|
301
|
+
try {
|
|
302
|
+
this.#usageLogger.error('op=usage_persist status=failed; 本轮用量未写入数据库');
|
|
303
|
+
}
|
|
304
|
+
catch { /* Transport failure cannot change delivery. */ }
|
|
305
|
+
}
|
|
306
|
+
}
|
|
270
307
|
}
|
|
271
308
|
}
|
|
272
|
-
#saveTrace(trace) {
|
|
309
|
+
#saveTrace(trace, context) {
|
|
273
310
|
trace.finalize();
|
|
311
|
+
const snapshot = trace.snapshot();
|
|
312
|
+
logTurnUsage(this.#usageLogger, snapshot, context);
|
|
274
313
|
// Fire-and-forget: a slow or failing trace write must not delay the reply.
|
|
275
|
-
void this.options.turnTraceStore?.save(
|
|
314
|
+
void this.options.turnTraceStore?.save(snapshot).catch(() => undefined);
|
|
276
315
|
}
|
|
277
316
|
}
|
|
278
317
|
function resolveTurnEngine(snapshot) {
|
|
@@ -338,11 +377,13 @@ export async function expandMcpTools(capabilities, allowedServers) {
|
|
|
338
377
|
}
|
|
339
378
|
return expanded;
|
|
340
379
|
}
|
|
341
|
-
function createIngressTurn(snapshot, request, capabilities, trace) {
|
|
380
|
+
function createIngressTurn(snapshot, request, capabilities, trace, usage) {
|
|
342
381
|
const journal = new PersistentTurnJournal({
|
|
343
382
|
sessionId: request.session.key,
|
|
344
383
|
turnId: request.identity.turnId,
|
|
345
384
|
}, resolveJournalStore(snapshot), request.principal);
|
|
385
|
+
const traced = trace ? createTracingJournal(journal, trace) : journal;
|
|
386
|
+
const observed = usage ? { append(event) { usage.record(event); return traced.append(event); } } : traced;
|
|
346
387
|
return createTurnIngress({
|
|
347
388
|
...request,
|
|
348
389
|
identity: {
|
|
@@ -357,7 +398,7 @@ function createIngressTurn(snapshot, request, capabilities, trace) {
|
|
|
357
398
|
},
|
|
358
399
|
ports: {
|
|
359
400
|
...request.ports,
|
|
360
|
-
journal: createJournalFeed(
|
|
401
|
+
journal: createJournalFeed(observed, {
|
|
361
402
|
turnId: request.identity.turnId,
|
|
362
403
|
}),
|
|
363
404
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-runtime.js","sourceRoot":"","sources":["../../src/plugin-runtime/agent-runtime.ts"],"names":[],"mappings":"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","sourcesContent":["import { createToken, type PluginId, type SnapshotLease, type SnapshotReader } from '@zhin.js/plugin-runtime';\nimport { applyTurnTrust } from '../security/trust-level.js';\nimport type { JournalStore } from '@zhin.js/ai/journal-store';\nimport { PersistentTurnJournal } from '../journal/persistent-turn-journal.js';\nimport { TurnTraceCollector } from '../trace/turn-trace.js';\nimport { createTracingJournal, registerTurnTrace } from '../trace/turn-trace-registry.js';\nimport { createJournalFeed } from '../turn/journal-feed.js';\nimport type { TurnTraceStore } from '../trace/turn-trace-store.js';\nimport { executeAgentTurn, type TurnEventObserver } from '../turn/execute-agent-turn.js';\nimport {\n createTurnIngress,\n type TurnOutcome,\n type TurnRequest,\n} from '../turn/turn-ingress.js';\nimport {\n CapabilityIngress,\n type AgentCapabilities,\n type ToolCapability,\n} from './capability-ingress.js';\nimport { TurnToolRuntime, type TurnToolOutcome } from '../tool/turn-tool-runtime.js';\nimport { requireToolInputSchema, type ToolDescriptor } from '@zhin.js/tool';\nimport type { ResolvedAgentBinding } from '../config/types.js';\nimport { runWithAgentTurnConfiguration } from '../turn/agent-turn-context.js';\nimport { TurnSupersededError } from '../turn/prompt-controller.js';\nimport { createConversationReferenceCapability } from '../tool/conversation-reference-tool.js';\nimport { drainAgentTurnDecisionObservations, runWithAgentDecisionTurn } from './decision-runtime.js';\nimport type { AgentDecisionRuntime } from '../decision/types.js';\n\nabstract class SnapshotAttachedRuntime {\n protected snapshots?: SnapshotReader;\n\n attach(snapshots: SnapshotReader): void {\n if (this.snapshots && this.snapshots !== snapshots) {\n throw new Error(`${this.constructor.name} is already attached to another Root`);\n }\n this.snapshots = snapshots;\n }\n\n protected requireSnapshots(): SnapshotReader {\n if (!this.snapshots) throw new Error(`${this.constructor.name} is not attached to a Root`);\n return this.snapshots;\n }\n}\n\nexport const turnJournalStoreToken = createToken<JournalStore>(\n 'zhin.agent.turn-journal-store',\n 'Durable Agent turn event journal store',\n);\n\nexport interface ExternalToolCapability extends ToolDescriptor {\n execute(input: Readonly<Record<string, unknown>>, toolUseId: string): Promise<TurnToolOutcome>;\n}\n\n/** Canonical fixed-generation execution authority for external tool protocols. */\nexport class ToolIngressRuntime extends SnapshotAttachedRuntime {\n readonly #ingress = new CapabilityIngress();\n\n async withTools<TResult>(\n owner: PluginId,\n request: TurnRequest,\n operation: (tools: readonly ExternalToolCapability[]) => TResult | Promise<TResult>,\n ): Promise<TResult> {\n const lease = this.requireSnapshots().acquire();\n let active = true;\n try {\n const capabilities = await this.#ingress.read(lease.value, owner, () => active, request);\n let invocationSequence = 0;\n const tools = Object.freeze(capabilities.tools\n .filter((tool) => !tool.hidden)\n .map(({ execute: _execute, ...descriptor }) => Object.freeze({\n ...descriptor,\n execute: async (input: Readonly<Record<string, unknown>>, toolUseId: string) => {\n if (!active) throw new Error('External Tool capability scope has ended');\n invocationSequence += 1;\n const invocationRequest: TurnRequest = {\n ...request,\n identity: {\n traceId: request.identity.traceId,\n turnId: `${request.identity.turnId}:${invocationSequence}`,\n },\n };\n const turn = createIngressTurn(lease.value, invocationRequest, capabilities);\n const runtime = new TurnToolRuntime(turn, capabilities.tools);\n const outcome = await runtime.execute(descriptor.name, input, toolUseId);\n await appendExternalToolTerminal(turn, outcome);\n return outcome;\n },\n })));\n return await operation(tools);\n } finally {\n active = false;\n lease.release();\n }\n }\n}\n\nasync function appendExternalToolTerminal(\n turn: import('../turn/turn-ingress.js').TurnIngress,\n outcome: TurnToolOutcome,\n): Promise<void> {\n if (outcome.status === 'completed') {\n await turn.ports.journal.append({\n type: 'turn_end',\n output: [],\n usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },\n });\n return;\n }\n if (outcome.status === 'cancelled') {\n await turn.ports.journal.append({\n type: 'turn_cancelled',\n code: 'cancelled',\n reason: outcome.reason,\n });\n return;\n }\n const message = outcome.status === 'failed' ? outcome.error : outcome.reason;\n await turn.ports.journal.append({\n type: 'error',\n error: new Error(message),\n recoverable: false,\n });\n}\n\n/** Single Agent execution authority: snapshot + capabilities + terminal algebra. */\nexport interface AgentTurnExecutionContext {\n readonly decision?: AgentDecisionRuntime;\n readonly turn: import('../turn/turn-ingress.js').TurnIngress;\n readonly capabilities: Omit<AgentCapabilities, 'tools'> & {\n readonly tools: readonly ToolDescriptor[];\n };\n readonly tools: TurnToolRuntime;\n /** Executable descriptors bound to the same active generation lease. */\n readonly toolCapabilities: readonly ToolCapability[];\n readonly selection: AgentCapabilitySelection;\n /** Signals that this ingress has reached the ordered PromptController boundary. */\n readonly admit?: () => void;\n}\n\n/** Root-owned serialization authority shared by every Agent generation. */\nexport class AgentTurnCoordinator {\n readonly #tails = new Map<string, Promise<void>>();\n readonly #admissions = new Map<string, Promise<void>>();\n readonly #active = new Map<string, AbortController>();\n\n async run<TResult>(\n sessionKey: string,\n signal: AbortSignal,\n operation: () => Promise<TResult>,\n ): Promise<TResult> {\n const previous = this.#tails.get(sessionKey) ?? Promise.resolve();\n let release!: () => void;\n const current = new Promise<void>((resolve) => { release = resolve; });\n const tail = previous.catch(() => undefined).then(() => current);\n this.#tails.set(sessionKey, tail);\n try {\n await waitForTurn(previous.catch(() => undefined), signal);\n return await operation();\n } finally {\n release();\n if (this.#tails.get(sessionKey) === tail) this.#tails.delete(sessionKey);\n }\n }\n\n async runIntent<TResult>(\n sessionKey: string,\n signal: AbortSignal,\n intent: import('../turn/turn-ingress.js').TurnIntent,\n _principal: import('../turn/turn-ingress.js').TurnPrincipal,\n operation: (admit: () => void, signal: AbortSignal) => Promise<TResult>,\n ): Promise<TResult> {\n const previous = this.#tails.get(sessionKey) ?? Promise.resolve();\n const previousAdmission = this.#admissions.get(sessionKey);\n let admit!: () => void;\n let complete!: () => void;\n const admitted = new Promise<void>((resolve) => { admit = once(resolve); });\n const completed = new Promise<void>((resolve) => { complete = once(resolve); });\n const cumulative = Promise.all([previous.catch(() => undefined), completed]).then(() => undefined);\n const controller = new AbortController();\n const abortFromCaller = () => controller.abort(signal.reason);\n if (signal.aborted) abortFromCaller();\n else signal.addEventListener('abort', abortFromCaller, { once: true });\n this.#tails.set(sessionKey, cumulative);\n void cumulative.finally(() => {\n if (this.#tails.get(sessionKey) === cumulative) this.#tails.delete(sessionKey);\n });\n this.#admissions.set(sessionKey, admitted);\n try {\n if (intent.kind === 'new') {\n await waitForTurn(previous.catch(() => undefined), signal);\n this.#active.set(sessionKey, controller);\n } else if (intent.kind === 'supersede') {\n await waitForAdmission(previousAdmission, signal);\n this.#active.get(sessionKey)?.abort(new TurnSupersededError(sessionKey));\n await waitForTurn(previous.catch(() => undefined), signal);\n this.#active.set(sessionKey, controller);\n } else {\n await waitForAdmission(previousAdmission, signal);\n }\n return await operation(admit, controller.signal);\n } finally {\n signal.removeEventListener('abort', abortFromCaller);\n admit();\n complete();\n if (this.#active.get(sessionKey) === controller) this.#active.delete(sessionKey);\n if (this.#admissions.get(sessionKey) === admitted) this.#admissions.delete(sessionKey);\n }\n }\n}\n\nexport type AgentTurnExecutor = (\n context: AgentTurnExecutionContext,\n) => AsyncGenerator<\n import('../event/turn-event.js').TurnEvent,\n import('../turn/execute-agent-turn.js').TurnTerminalProjection | void\n>;\n\n/** Generation-owned complete Turn engine resolved from the held snapshot. */\nexport interface AgentTurnEngine {\n run: AgentTurnExecutor;\n}\n\nexport const agentTurnEngineToken = createToken<AgentTurnEngine>(\n 'zhin.agent.turn-engine',\n 'Complete Agent Turn engine owned by one Root generation',\n);\n\nexport interface AgentRuntimeOptions {\n /** Root-owned queue shared by every AgentRuntime generation of that Root. */\n readonly coordinator: AgentTurnCoordinator;\n /** Where finished TurnTraces go (`zhin trace`). Omit to disable tracing. */\n readonly turnTraceStore?: TurnTraceStore;\n}\n\nexport interface AgentCapabilitySelection {\n /** Immutable model/provider binding selected for this turn. */\n readonly binding: ResolvedAgentBinding;\n /** Binding-local MCP names. Empty means no MCP capability is exposed. */\n readonly mcpServers: readonly string[];\n /** Optional owner-visible specialist selected by the ingress router. */\n readonly agent?: string;\n}\n\nexport class AgentRuntime extends SnapshotAttachedRuntime {\n readonly #ingress = new CapabilityIngress();\n\n constructor(private readonly options: AgentRuntimeOptions) {\n super();\n }\n\n async execute(\n owner: PluginId,\n request: TurnRequest,\n selection: AgentCapabilitySelection,\n observe?: TurnEventObserver,\n ): Promise<TurnOutcome> {\n const lease = this.requireSnapshots().acquire();\n try {\n return await this.executeLeased(lease, owner, request, selection, observe);\n } finally {\n lease.release();\n }\n }\n\n /** Executes under the fixed-generation lease owned by the ingress operation. */\n async executeLeased(\n lease: SnapshotLease,\n owner: PluginId,\n request: TurnRequest,\n selection: AgentCapabilitySelection,\n observe?: TurnEventObserver,\n ): Promise<TurnOutcome> {\n const snapshots = this.requireSnapshots();\n if (!snapshots.owns(lease)) throw new Error('AgentRuntime rejected a lease owned by another Root');\n if (!lease.active) throw new Error('AgentRuntime requires an active generation lease');\n if (!request.intent) throw new TypeError('AgentRuntime requires an explicit Turn intent');\n const intent = request.intent;\n return this.options.coordinator.runIntent(\n request.session.key,\n request.signal,\n intent,\n request.principal,\n (admit, signal) => this.#executeLeased(\n lease,\n owner,\n { ...request, signal },\n selection,\n observe,\n admit,\n ),\n );\n }\n\n async #executeLeased(\n lease: SnapshotLease,\n owner: PluginId,\n request: TurnRequest,\n selection: AgentCapabilitySelection,\n observe?: TurnEventObserver,\n admit: () => void = () => undefined,\n ): Promise<TurnOutcome> {\n let active = true;\n let activeTrace: TurnTraceCollector | undefined;\n let releaseTrace: (() => void) | undefined;\n try {\n if (!active) throw new Error('Agent generation operation is not active');\n const discovered = await this.#ingress.read(\n lease.value,\n owner,\n () => active && lease.active,\n request,\n selection.agent,\n );\n const referenceCapability = createConversationReferenceCapability(owner, request);\n // #726: the initiator's trust level caps the turn (group members: no shell, writes or outbound).\n const allTools = [\n ...discovered.tools,\n ...(referenceCapability ? [referenceCapability] : []),\n ...await expandMcpTools(discovered, selection.mcpServers),\n ];\n const trust = applyTurnTrust(request, allTools);\n const capabilities = Object.freeze({\n ...discovered,\n tools: Object.freeze([...trust.tools]),\n });\n const turnRequest = trust.restricted\n ? Object.freeze({ ...request, policy: trust.policy })\n : request;\n const trace = this.options.turnTraceStore\n ? new TurnTraceCollector({\n turnId: request.identity.turnId,\n sessionKey: request.session.key,\n principal: { ...request.principal, trustLevel: trust.level },\n })\n : undefined;\n releaseTrace = trace ? registerTurnTrace(trace) : undefined;\n activeTrace = trace;\n const turn = createIngressTurn(lease.value, turnRequest, capabilities, trace);\n const catalog = Object.freeze({\n ...capabilities,\n tools: Object.freeze(capabilities.tools.map(({ execute: _execute, ...tool }) => Object.freeze(tool))),\n });\n const tools = new TurnToolRuntime(turn, capabilities.tools);\n const engine = resolveTurnEngine(lease.value);\n const disabled = Boolean(request.session.key.startsWith('workroom:') || request.input.metadata?.workroom\n || request.principal.roles.includes('workroom_assignment') || request.execution?.kind === 'schedule');\n return await runWithAgentDecisionTurn(lease.value, request.identity.turnId, decision => runWithAgentTurnConfiguration(\n { activeBinding: selection.binding },\n () => executeAgentTurn(turn, async function* () {\n const stream = engine.run({\n turn,\n capabilities: catalog,\n tools,\n toolCapabilities: capabilities.tools,\n selection,\n decision,\n admit,\n });\n try {\n while (true) {\n const next = await stream.next();\n for (const observation of drainAgentTurnDecisionObservations()) {\n yield { type: 'decision_evaluation', ...observation };\n }\n if (next.done) return next.value;\n yield next.value;\n }\n } catch (error) {\n // A later engine failure must not erase already completed decisions.\n for (const observation of drainAgentTurnDecisionObservations()) {\n yield { type: 'decision_evaluation', ...observation };\n }\n throw error;\n } finally {\n await stream.return(undefined);\n }\n }, observe),\n ), { disabled });\n } finally {\n active = false;\n releaseTrace?.();\n if (activeTrace) this.#saveTrace(activeTrace);\n }\n }\n\n #saveTrace(trace: TurnTraceCollector): void {\n trace.finalize();\n // Fire-and-forget: a slow or failing trace write must not delay the reply.\n void this.options.turnTraceStore?.save(trace.snapshot()).catch(() => undefined);\n }\n}\n\nfunction resolveTurnEngine(snapshot: import('@zhin.js/plugin-runtime').RuntimeSnapshot): AgentTurnEngine {\n const candidate = snapshot.resources.get(snapshot.root)?.get(agentTurnEngineToken.id);\n if (!candidate || typeof (candidate as AgentTurnEngine).run !== 'function') {\n throw new Error('Active generation does not provide an Agent Turn Engine');\n }\n return candidate as AgentTurnEngine;\n}\n\nasync function waitForTurn(previous: Promise<void>, signal: AbortSignal): Promise<void> {\n if (signal.aborted) throw signal.reason ?? new Error('Agent turn cancelled while queued');\n let rejectAbort!: (reason: unknown) => void;\n const aborted = new Promise<never>((_resolve, reject) => { rejectAbort = reject; });\n const onAbort = () => rejectAbort(signal.reason ?? new Error('Agent turn cancelled while queued'));\n signal.addEventListener('abort', onAbort, { once: true });\n try {\n await Promise.race([previous, aborted]);\n } finally {\n signal.removeEventListener('abort', onAbort);\n }\n}\n\nasync function waitForAdmission(previous: Promise<void> | undefined, signal: AbortSignal): Promise<void> {\n if (!previous) return;\n await waitForTurn(previous.catch(() => undefined), signal);\n}\n\nfunction once(callback: () => void): () => void {\n let called = false;\n return () => {\n if (called) return;\n called = true;\n callback();\n };\n}\n\nexport async function expandMcpTools(\n capabilities: AgentCapabilities,\n allowedServers: readonly string[],\n): Promise<ToolCapability[]> {\n const expanded: ToolCapability[] = [];\n const occupied = new Set(capabilities.tools.map((tool) => tool.name));\n for (const connection of capabilities.mcp) {\n if (!allowedServers.includes(connection.name)) continue;\n for (const tool of await connection.listTools()) {\n const name = `${connection.qualifiedName}__${tool.name}`;\n if (occupied.has(name)) {\n throw new Error(`Duplicate Agent Tool capability: ${name}`);\n }\n occupied.add(name);\n expanded.push(Object.freeze({\n owner: connection.owner,\n name,\n qualifiedName: name,\n description: tool.description?.trim() || `${connection.name} MCP tool ${tool.name}`,\n inputSchema: tool.inputSchema === undefined\n ? undefined\n : requireToolInputSchema(tool.inputSchema, `MCP Tool ${name} inputSchema`),\n requiresApproval: 'on-risk' as const,\n source: connection.source,\n execute: <TInput = unknown, TResult = unknown>(input: TInput) =>\n connection.callTool<TResult>(tool.name, input),\n }));\n }\n }\n return expanded;\n}\n\nfunction createIngressTurn(\n snapshot: import('@zhin.js/plugin-runtime').RuntimeSnapshot,\n request: TurnRequest,\n capabilities: AgentCapabilities,\n trace?: TurnTraceCollector,\n) {\n const journal = new PersistentTurnJournal({\n sessionId: request.session.key,\n turnId: request.identity.turnId,\n }, resolveJournalStore(snapshot), request.principal);\n return createTurnIngress({\n ...request,\n identity: {\n rootId: String(snapshot.root),\n generation: snapshot.generation,\n traceId: request.identity.traceId,\n turnId: request.identity.turnId,\n },\n capabilities: {\n tools: capabilities.tools.map((tool) => tool.name),\n skills: capabilities.skills.map((skill) => skill.name),\n },\n ports: {\n ...request.ports,\n journal: createJournalFeed(trace ? createTracingJournal(journal, trace) : journal, {\n turnId: request.identity.turnId,\n }),\n },\n });\n}\n\nfunction resolveJournalStore(snapshot: import('@zhin.js/plugin-runtime').RuntimeSnapshot): JournalStore {\n const store = snapshot.resources.get(snapshot.root)?.get(turnJournalStoreToken.id);\n if (!store\n || typeof (store as JournalStore).append !== 'function'\n || typeof (store as JournalStore).replay !== 'function') {\n throw new Error('Agent Turn JournalStore is not installed for this generation');\n }\n return store as JournalStore;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"agent-runtime.js","sourceRoot":"","sources":["../../src/plugin-runtime/agent-runtime.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TurnEvent } from '../event/turn-event.js';\nimport { AgentUsageCollector, agentUsageStoreToken, type AgentUsageStore } from '../usage/usage-store.js';\nimport { getLogger } from '@zhin.js/logger';\nimport { logTurnUsage, type UsageLogContext } from '../trace/turn-usage-log.js';\nimport { createToken, type PluginId, type SnapshotLease, type SnapshotReader } from '@zhin.js/plugin-runtime';\nimport { applyTurnTrust } from '../security/trust-level.js';\nimport type { JournalStore } from '@zhin.js/ai/journal-store';\nimport { PersistentTurnJournal } from '../journal/persistent-turn-journal.js';\nimport { TurnTraceCollector } from '../trace/turn-trace.js';\nimport { createTracingJournal, registerTurnTrace } from '../trace/turn-trace-registry.js';\nimport { createJournalFeed } from '../turn/journal-feed.js';\nimport type { TurnTraceStore } from '../trace/turn-trace-store.js';\nimport { executeAgentTurn, type TurnEventObserver } from '../turn/execute-agent-turn.js';\nimport {\n createTurnIngress,\n type TurnOutcome,\n type TurnRequest,\n} from '../turn/turn-ingress.js';\nimport {\n CapabilityIngress,\n type AgentCapabilities,\n type ToolCapability,\n} from './capability-ingress.js';\nimport { TurnToolRuntime, type TurnToolOutcome } from '../tool/turn-tool-runtime.js';\nimport { requireToolInputSchema, type ToolDescriptor } from '@zhin.js/tool';\nimport type { ResolvedAgentBinding } from '../config/types.js';\nimport { runWithAgentTurnConfiguration } from '../turn/agent-turn-context.js';\nimport { TurnSupersededError } from '../turn/prompt-controller.js';\nimport { createConversationReferenceCapability } from '../tool/conversation-reference-tool.js';\nimport { drainAgentTurnDecisionObservations, runWithAgentDecisionTurn } from './decision-runtime.js';\nimport type { AgentDecisionRuntime } from '../decision/types.js';\n\nabstract class SnapshotAttachedRuntime {\n protected snapshots?: SnapshotReader;\n\n attach(snapshots: SnapshotReader): void {\n if (this.snapshots && this.snapshots !== snapshots) {\n throw new Error(`${this.constructor.name} is already attached to another Root`);\n }\n this.snapshots = snapshots;\n }\n\n protected requireSnapshots(): SnapshotReader {\n if (!this.snapshots) throw new Error(`${this.constructor.name} is not attached to a Root`);\n return this.snapshots;\n }\n}\n\nexport const turnJournalStoreToken = createToken<JournalStore>(\n 'zhin.agent.turn-journal-store',\n 'Durable Agent turn event journal store',\n);\n\nexport interface ExternalToolCapability extends ToolDescriptor {\n execute(input: Readonly<Record<string, unknown>>, toolUseId: string): Promise<TurnToolOutcome>;\n}\n\n/** Canonical fixed-generation execution authority for external tool protocols. */\nexport class ToolIngressRuntime extends SnapshotAttachedRuntime {\n readonly #ingress = new CapabilityIngress();\n\n async withTools<TResult>(\n owner: PluginId,\n request: TurnRequest,\n operation: (tools: readonly ExternalToolCapability[]) => TResult | Promise<TResult>,\n ): Promise<TResult> {\n const lease = this.requireSnapshots().acquire();\n let active = true;\n try {\n const capabilities = await this.#ingress.read(lease.value, owner, () => active, request);\n let invocationSequence = 0;\n const tools = Object.freeze(capabilities.tools\n .filter((tool) => !tool.hidden)\n .map(({ execute: _execute, ...descriptor }) => Object.freeze({\n ...descriptor,\n execute: async (input: Readonly<Record<string, unknown>>, toolUseId: string) => {\n if (!active) throw new Error('External Tool capability scope has ended');\n invocationSequence += 1;\n const invocationRequest: TurnRequest = {\n ...request,\n identity: {\n traceId: request.identity.traceId,\n turnId: `${request.identity.turnId}:${invocationSequence}`,\n },\n };\n const turn = createIngressTurn(lease.value, invocationRequest, capabilities);\n const runtime = new TurnToolRuntime(turn, capabilities.tools);\n const outcome = await runtime.execute(descriptor.name, input, toolUseId);\n await appendExternalToolTerminal(turn, outcome);\n return outcome;\n },\n })));\n return await operation(tools);\n } finally {\n active = false;\n lease.release();\n }\n }\n}\n\nasync function appendExternalToolTerminal(\n turn: import('../turn/turn-ingress.js').TurnIngress,\n outcome: TurnToolOutcome,\n): Promise<void> {\n if (outcome.status === 'completed') {\n await turn.ports.journal.append({\n type: 'turn_end',\n output: [],\n usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },\n });\n return;\n }\n if (outcome.status === 'cancelled') {\n await turn.ports.journal.append({\n type: 'turn_cancelled',\n code: 'cancelled',\n reason: outcome.reason,\n });\n return;\n }\n const message = outcome.status === 'failed' ? outcome.error : outcome.reason;\n await turn.ports.journal.append({\n type: 'error',\n error: new Error(message),\n recoverable: false,\n });\n}\n\n/** Single Agent execution authority: snapshot + capabilities + terminal algebra. */\nexport interface AgentTurnExecutionContext {\n readonly decision?: AgentDecisionRuntime;\n readonly turn: import('../turn/turn-ingress.js').TurnIngress;\n readonly capabilities: Omit<AgentCapabilities, 'tools'> & {\n readonly tools: readonly ToolDescriptor[];\n };\n readonly tools: TurnToolRuntime;\n /** Executable descriptors bound to the same active generation lease. */\n readonly toolCapabilities: readonly ToolCapability[];\n readonly selection: AgentCapabilitySelection;\n /** Signals that this ingress has reached the ordered PromptController boundary. */\n readonly admit?: () => void;\n}\n\n/** Root-owned serialization authority shared by every Agent generation. */\nexport class AgentTurnCoordinator {\n readonly #tails = new Map<string, Promise<void>>();\n readonly #admissions = new Map<string, Promise<void>>();\n readonly #active = new Map<string, AbortController>();\n\n async run<TResult>(\n sessionKey: string,\n signal: AbortSignal,\n operation: () => Promise<TResult>,\n ): Promise<TResult> {\n const previous = this.#tails.get(sessionKey) ?? Promise.resolve();\n let release!: () => void;\n const current = new Promise<void>((resolve) => { release = resolve; });\n const tail = previous.catch(() => undefined).then(() => current);\n this.#tails.set(sessionKey, tail);\n try {\n await waitForTurn(previous.catch(() => undefined), signal);\n return await operation();\n } finally {\n release();\n if (this.#tails.get(sessionKey) === tail) this.#tails.delete(sessionKey);\n }\n }\n\n async runIntent<TResult>(\n sessionKey: string,\n signal: AbortSignal,\n intent: import('../turn/turn-ingress.js').TurnIntent,\n _principal: import('../turn/turn-ingress.js').TurnPrincipal,\n operation: (admit: () => void, signal: AbortSignal) => Promise<TResult>,\n ): Promise<TResult> {\n const previous = this.#tails.get(sessionKey) ?? Promise.resolve();\n const previousAdmission = this.#admissions.get(sessionKey);\n let admit!: () => void;\n let complete!: () => void;\n const admitted = new Promise<void>((resolve) => { admit = once(resolve); });\n const completed = new Promise<void>((resolve) => { complete = once(resolve); });\n const cumulative = Promise.all([previous.catch(() => undefined), completed]).then(() => undefined);\n const controller = new AbortController();\n const abortFromCaller = () => controller.abort(signal.reason);\n if (signal.aborted) abortFromCaller();\n else signal.addEventListener('abort', abortFromCaller, { once: true });\n this.#tails.set(sessionKey, cumulative);\n void cumulative.finally(() => {\n if (this.#tails.get(sessionKey) === cumulative) this.#tails.delete(sessionKey);\n });\n this.#admissions.set(sessionKey, admitted);\n try {\n if (intent.kind === 'new') {\n await waitForTurn(previous.catch(() => undefined), signal);\n this.#active.set(sessionKey, controller);\n } else if (intent.kind === 'supersede') {\n await waitForAdmission(previousAdmission, signal);\n this.#active.get(sessionKey)?.abort(new TurnSupersededError(sessionKey));\n await waitForTurn(previous.catch(() => undefined), signal);\n this.#active.set(sessionKey, controller);\n } else {\n await waitForAdmission(previousAdmission, signal);\n }\n return await operation(admit, controller.signal);\n } finally {\n signal.removeEventListener('abort', abortFromCaller);\n admit();\n complete();\n if (this.#active.get(sessionKey) === controller) this.#active.delete(sessionKey);\n if (this.#admissions.get(sessionKey) === admitted) this.#admissions.delete(sessionKey);\n }\n }\n}\n\nexport type AgentTurnExecutor = (\n context: AgentTurnExecutionContext,\n) => AsyncGenerator<\n import('../event/turn-event.js').TurnEvent,\n import('../turn/execute-agent-turn.js').TurnTerminalProjection | void\n>;\n\n/** Generation-owned complete Turn engine resolved from the held snapshot. */\nexport interface AgentTurnEngine {\n run: AgentTurnExecutor;\n}\n\nexport const agentTurnEngineToken = createToken<AgentTurnEngine>(\n 'zhin.agent.turn-engine',\n 'Complete Agent Turn engine owned by one Root generation',\n);\n\nexport interface AgentRuntimeOptions {\n /** Root-owned queue shared by every AgentRuntime generation of that Root. */\n readonly coordinator: AgentTurnCoordinator;\n /** Where finished TurnTraces go (`zhin trace`). Omit to disable tracing. */\n readonly turnTraceStore?: TurnTraceStore;\n}\n\nexport interface AgentCapabilitySelection {\n /** Immutable model/provider binding selected for this turn. */\n readonly binding: ResolvedAgentBinding;\n /** Binding-local MCP names. Empty means no MCP capability is exposed. */\n readonly mcpServers: readonly string[];\n /** Optional owner-visible specialist selected by the ingress router. */\n readonly agent?: string;\n}\n\nexport class AgentRuntime extends SnapshotAttachedRuntime {\n readonly #ingress = new CapabilityIngress();\n readonly #usageLogger = getLogger('ai.usage');\n\n constructor(private readonly options: AgentRuntimeOptions) {\n super();\n }\n\n async execute(\n owner: PluginId,\n request: TurnRequest,\n selection: AgentCapabilitySelection,\n observe?: TurnEventObserver,\n ): Promise<TurnOutcome> {\n const lease = this.requireSnapshots().acquire();\n try {\n return await this.executeLeased(lease, owner, request, selection, observe);\n } finally {\n lease.release();\n }\n }\n\n /** Executes under the fixed-generation lease owned by the ingress operation. */\n async executeLeased(\n lease: SnapshotLease,\n owner: PluginId,\n request: TurnRequest,\n selection: AgentCapabilitySelection,\n observe?: TurnEventObserver,\n ): Promise<TurnOutcome> {\n const snapshots = this.requireSnapshots();\n if (!snapshots.owns(lease)) throw new Error('AgentRuntime rejected a lease owned by another Root');\n if (!lease.active) throw new Error('AgentRuntime requires an active generation lease');\n if (!request.intent) throw new TypeError('AgentRuntime requires an explicit Turn intent');\n const intent = request.intent;\n return this.options.coordinator.runIntent(\n request.session.key,\n request.signal,\n intent,\n request.principal,\n (admit, signal) => this.#executeLeased(\n lease,\n owner,\n { ...request, signal },\n selection,\n observe,\n admit,\n ),\n );\n }\n\n async #executeLeased(\n lease: SnapshotLease,\n owner: PluginId,\n request: TurnRequest,\n selection: AgentCapabilitySelection,\n observe?: TurnEventObserver,\n admit: () => void = () => undefined,\n ): Promise<TurnOutcome> {\n let active = true;\n const usageStore = lease.value.resources.get(lease.value.root)?.get(agentUsageStoreToken.id) as AgentUsageStore | undefined;\n const usage = usageStore ? new AgentUsageCollector(String(owner), request, {\n provider: selection.binding.providerAlias, model: selection.binding.model,\n }) : undefined;\n let usageStatus = 'failed';\n let activeTrace: TurnTraceCollector | undefined;\n let releaseTrace: (() => void) | undefined;\n let outcome: TurnOutcome | undefined;\n const logContext: UsageLogContext = {\n traceId: request.identity.traceId,\n scene: request.origin.kind === 'im' ? `${request.origin.platform}/${request.origin.scope}` : request.origin.kind,\n selectedModel: `${selection.binding.providerAlias}/${selection.binding.model}`,\n };\n try {\n if (!active) throw new Error('Agent generation operation is not active');\n const discovered = await this.#ingress.read(\n lease.value,\n owner,\n () => active && lease.active,\n request,\n selection.agent,\n );\n const referenceCapability = createConversationReferenceCapability(owner, request);\n // #726: the initiator's trust level caps the turn (group members: no shell, writes or outbound).\n const allTools = [\n ...discovered.tools,\n ...(referenceCapability ? [referenceCapability] : []),\n ...await expandMcpTools(discovered, selection.mcpServers),\n ];\n const trust = applyTurnTrust(request, allTools);\n const capabilities = Object.freeze({\n ...discovered,\n tools: Object.freeze([...trust.tools]),\n });\n const turnRequest = trust.restricted\n ? Object.freeze({ ...request, policy: trust.policy })\n : request;\n const trace = this.options.turnTraceStore || this.#usageLogger.isLevelEnabled('info')\n ? new TurnTraceCollector({\n turnId: request.identity.turnId,\n sessionKey: request.session.key,\n principal: { ...request.principal, trustLevel: trust.level },\n })\n : undefined;\n releaseTrace = trace ? registerTurnTrace(trace) : undefined;\n activeTrace = trace;\n const turn = createIngressTurn(lease.value, turnRequest, capabilities, trace, usage);\n const catalog = Object.freeze({\n ...capabilities,\n tools: Object.freeze(capabilities.tools.map(({ execute: _execute, ...tool }) => Object.freeze(tool))),\n });\n const tools = new TurnToolRuntime(turn, capabilities.tools);\n const engine = resolveTurnEngine(lease.value);\n const disabled = Boolean(request.session.key.startsWith('workroom:') || request.input.metadata?.workroom\n || request.principal.roles.includes('workroom_assignment') || request.execution?.kind === 'schedule');\n outcome = await runWithAgentDecisionTurn(lease.value, request.identity.turnId, decision => runWithAgentTurnConfiguration(\n { activeBinding: selection.binding },\n () => executeAgentTurn(turn, async function* () {\n const stream = engine.run({\n turn,\n capabilities: catalog,\n tools,\n toolCapabilities: capabilities.tools,\n selection,\n decision,\n admit,\n });\n try {\n while (true) {\n const next = await stream.next();\n for (const observation of drainAgentTurnDecisionObservations()) {\n yield { type: 'decision_evaluation', ...observation };\n }\n if (next.done) return next.value;\n yield next.value;\n }\n } catch (error) {\n // A later engine failure must not erase already completed decisions.\n for (const observation of drainAgentTurnDecisionObservations()) {\n yield { type: 'decision_evaluation', ...observation };\n }\n throw error;\n } finally {\n await stream.return(undefined);\n }\n }, observe),\n ), { disabled });\n usageStatus = outcome.status;\n return outcome;\n } catch (error) {\n usageStatus = request.signal.aborted ? 'cancelled' : 'failed';\n if (!activeTrace && this.#usageLogger.isLevelEnabled('info')) {\n activeTrace = new TurnTraceCollector({ turnId: request.identity.turnId, sessionKey: request.session.key });\n }\n activeTrace?.finalize({ status: request.signal.aborted ? 'cancelled' : 'failed' });\n throw error;\n } finally {\n active = false;\n releaseTrace?.();\n if (activeTrace) this.#saveTrace(activeTrace, { ...logContext, status: outcome?.status });\n if (usage && usageStore) {\n try { await usageStore.save(usage.finish(usageStatus)); }\n catch {\n // No model response, prompt or database error text enters this diagnostic.\n try { this.#usageLogger.error('op=usage_persist status=failed; 本轮用量未写入数据库'); } catch { /* Transport failure cannot change delivery. */ }\n }\n }\n }\n }\n\n #saveTrace(trace: TurnTraceCollector, context: UsageLogContext): void {\n trace.finalize();\n const snapshot = trace.snapshot();\n logTurnUsage(this.#usageLogger, snapshot, context);\n // Fire-and-forget: a slow or failing trace write must not delay the reply.\n void this.options.turnTraceStore?.save(snapshot).catch(() => undefined);\n }\n}\n\nfunction resolveTurnEngine(snapshot: import('@zhin.js/plugin-runtime').RuntimeSnapshot): AgentTurnEngine {\n const candidate = snapshot.resources.get(snapshot.root)?.get(agentTurnEngineToken.id);\n if (!candidate || typeof (candidate as AgentTurnEngine).run !== 'function') {\n throw new Error('Active generation does not provide an Agent Turn Engine');\n }\n return candidate as AgentTurnEngine;\n}\n\nasync function waitForTurn(previous: Promise<void>, signal: AbortSignal): Promise<void> {\n if (signal.aborted) throw signal.reason ?? new Error('Agent turn cancelled while queued');\n let rejectAbort!: (reason: unknown) => void;\n const aborted = new Promise<never>((_resolve, reject) => { rejectAbort = reject; });\n const onAbort = () => rejectAbort(signal.reason ?? new Error('Agent turn cancelled while queued'));\n signal.addEventListener('abort', onAbort, { once: true });\n try {\n await Promise.race([previous, aborted]);\n } finally {\n signal.removeEventListener('abort', onAbort);\n }\n}\n\nasync function waitForAdmission(previous: Promise<void> | undefined, signal: AbortSignal): Promise<void> {\n if (!previous) return;\n await waitForTurn(previous.catch(() => undefined), signal);\n}\n\nfunction once(callback: () => void): () => void {\n let called = false;\n return () => {\n if (called) return;\n called = true;\n callback();\n };\n}\n\nexport async function expandMcpTools(\n capabilities: AgentCapabilities,\n allowedServers: readonly string[],\n): Promise<ToolCapability[]> {\n const expanded: ToolCapability[] = [];\n const occupied = new Set(capabilities.tools.map((tool) => tool.name));\n for (const connection of capabilities.mcp) {\n if (!allowedServers.includes(connection.name)) continue;\n for (const tool of await connection.listTools()) {\n const name = `${connection.qualifiedName}__${tool.name}`;\n if (occupied.has(name)) {\n throw new Error(`Duplicate Agent Tool capability: ${name}`);\n }\n occupied.add(name);\n expanded.push(Object.freeze({\n owner: connection.owner,\n name,\n qualifiedName: name,\n description: tool.description?.trim() || `${connection.name} MCP tool ${tool.name}`,\n inputSchema: tool.inputSchema === undefined\n ? undefined\n : requireToolInputSchema(tool.inputSchema, `MCP Tool ${name} inputSchema`),\n requiresApproval: 'on-risk' as const,\n source: connection.source,\n execute: <TInput = unknown, TResult = unknown>(input: TInput) =>\n connection.callTool<TResult>(tool.name, input),\n }));\n }\n }\n return expanded;\n}\n\nfunction createIngressTurn(\n snapshot: import('@zhin.js/plugin-runtime').RuntimeSnapshot,\n request: TurnRequest,\n capabilities: AgentCapabilities,\n trace?: TurnTraceCollector,\n usage?: AgentUsageCollector,\n) {\n const journal = new PersistentTurnJournal({\n sessionId: request.session.key,\n turnId: request.identity.turnId,\n }, resolveJournalStore(snapshot), request.principal);\n const traced = trace ? createTracingJournal(journal, trace) : journal;\n const observed = usage ? { append(event: TurnEvent) { usage.record(event); return traced.append(event); } } : traced;\n return createTurnIngress({\n ...request,\n identity: {\n rootId: String(snapshot.root),\n generation: snapshot.generation,\n traceId: request.identity.traceId,\n turnId: request.identity.turnId,\n },\n capabilities: {\n tools: capabilities.tools.map((tool) => tool.name),\n skills: capabilities.skills.map((skill) => skill.name),\n },\n ports: {\n ...request.ports,\n journal: createJournalFeed(observed, {\n turnId: request.identity.turnId,\n }),\n },\n });\n}\n\nfunction resolveJournalStore(snapshot: import('@zhin.js/plugin-runtime').RuntimeSnapshot): JournalStore {\n const store = snapshot.resources.get(snapshot.root)?.get(turnJournalStoreToken.id);\n if (!store\n || typeof (store as JournalStore).append !== 'function'\n || typeof (store as JournalStore).replay !== 'function') {\n throw new Error('Agent Turn JournalStore is not installed for this generation');\n }\n return store as JournalStore;\n}\n"]}
|
|
@@ -6,17 +6,18 @@ import type { UsageQuota } from '../security/usage-quota.js';
|
|
|
6
6
|
* `zhin.js` main entry without this package; re-exported here unchanged (same token object and id).
|
|
7
7
|
*/
|
|
8
8
|
export { aiCompletionToken } from '@zhin.js/core';
|
|
9
|
-
export type { AiCompletion, AiCompletionInput, AiCompletionResult, AiCompletionUntrustedInput, UsageSubject, } from '@zhin.js/core';
|
|
9
|
+
export type { AiCompletion, AiCompletionInput, AiCompletionResult, AiCompletionUntrustedInput, AiCompletionUsageShare, UsageSubject, } from '@zhin.js/core';
|
|
10
10
|
/** Thrown when the `onBehalfOf` user or group is over its usage quota; `message` is user-facing. Recognise it with `isAiCompletionQuotaError`. */
|
|
11
11
|
export declare class AiCompletionQuotaError extends Error {
|
|
12
12
|
readonly name: "AiCompletionQuotaError";
|
|
13
13
|
readonly scope: 'user' | 'group';
|
|
14
14
|
readonly retryAfterSeconds: number;
|
|
15
|
-
|
|
15
|
+
readonly deniedUserIds?: readonly string[];
|
|
16
|
+
constructor(message: string, scope: 'user' | 'group', retryAfterSeconds: number, deniedUserIds?: readonly string[]);
|
|
16
17
|
}
|
|
17
18
|
export interface AiCompletionOptions {
|
|
18
19
|
readonly service: Pick<AIService, 'getBindingRegistry' | 'getProvider' | 'getAgentConfig'> & Partial<Pick<AIService, 'getModelRegistry'>>;
|
|
19
|
-
readonly usageQuota?: Pick<UsageQuota, 'check' | 'record'
|
|
20
|
+
readonly usageQuota?: Pick<UsageQuota, 'check' | 'record'> & Partial<Pick<UsageQuota, 'checkBatch'>>;
|
|
20
21
|
readonly now?: () => number;
|
|
21
22
|
}
|
|
22
23
|
export declare function createAiCompletion(options: AiCompletionOptions): AiCompletion;
|
|
@@ -29,28 +29,37 @@ export class AiCompletionQuotaError extends Error {
|
|
|
29
29
|
name = 'AiCompletionQuotaError';
|
|
30
30
|
scope;
|
|
31
31
|
retryAfterSeconds;
|
|
32
|
-
|
|
32
|
+
deniedUserIds;
|
|
33
|
+
constructor(message, scope, retryAfterSeconds, deniedUserIds) {
|
|
33
34
|
super(message);
|
|
34
35
|
this.scope = scope;
|
|
35
36
|
this.retryAfterSeconds = retryAfterSeconds;
|
|
37
|
+
this.deniedUserIds = deniedUserIds;
|
|
36
38
|
}
|
|
37
39
|
}
|
|
38
40
|
export function createAiCompletion(options) {
|
|
39
41
|
const now = options.now ?? Date.now;
|
|
40
42
|
return Object.freeze({
|
|
43
|
+
...(options.usageQuota && !options.usageQuota.checkBatch ? {} : { supportsUsageShares: true }),
|
|
41
44
|
async completeText(input) {
|
|
42
45
|
const purpose = requiredText(input.purpose, 'purpose');
|
|
43
46
|
const prompt = requiredText(input.prompt, 'prompt');
|
|
47
|
+
const shares = usageShares(input);
|
|
44
48
|
const registry = options.service.getBindingRegistry();
|
|
45
49
|
const binding = input.agent ? registry.getBinding(input.agent) : registry.requireZhinBinding();
|
|
46
50
|
if (!binding)
|
|
47
51
|
throw new Error(`AI completion: agent binding "${input.agent}" not found`);
|
|
48
52
|
const provider = options.service.getProvider(binding.providerAlias);
|
|
49
53
|
const model = input.model?.trim() || binding.model || provider.models[0] || '';
|
|
50
|
-
|
|
51
|
-
|
|
54
|
+
input.signal?.throwIfAborted();
|
|
55
|
+
if (shares.length && options.usageQuota) {
|
|
56
|
+
if (input.usageShares && !options.usageQuota.checkBatch)
|
|
57
|
+
throw new Error('AI completion: quota does not support shared attribution');
|
|
58
|
+
const decision = input.usageShares
|
|
59
|
+
? options.usageQuota.checkBatch(shares.map(share => share.subject))
|
|
60
|
+
: options.usageQuota.check(shares[0].subject);
|
|
52
61
|
if (!decision.allowed) {
|
|
53
|
-
throw new AiCompletionQuotaError(decision.message, decision.scope, decision.retryAfterSeconds);
|
|
62
|
+
throw new AiCompletionQuotaError(decision.message, decision.scope, decision.retryAfterSeconds, 'deniedUserIds' in decision ? decision.deniedUserIds : undefined);
|
|
54
63
|
}
|
|
55
64
|
}
|
|
56
65
|
const user = [
|
|
@@ -70,10 +79,18 @@ export function createAiCompletion(options) {
|
|
|
70
79
|
};
|
|
71
80
|
// Reserve the prompt estimate before the call: concurrent calls then see each other's
|
|
72
81
|
// spend at `check`, and a call that fails after reaching the provider is still billed.
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
options.usageQuota
|
|
82
|
+
const reserved = shares.length && options.usageQuota ? estimatePromptTokens(`${input.system ?? ''}\n${user}`) : 0;
|
|
83
|
+
let billed = shares.map(() => 0);
|
|
84
|
+
const record = (tokens) => {
|
|
85
|
+
if (!options.usageQuota || tokens <= 0)
|
|
86
|
+
return;
|
|
87
|
+
const allocated = allocateTokens(tokens, shares.map(share => share.weight));
|
|
88
|
+
shares.forEach((share, index) => {
|
|
89
|
+
options.usageQuota.record(share.subject, allocated[index] - billed[index]);
|
|
90
|
+
});
|
|
91
|
+
billed = allocated;
|
|
92
|
+
};
|
|
93
|
+
record(reserved);
|
|
77
94
|
const started = now();
|
|
78
95
|
let result;
|
|
79
96
|
try {
|
|
@@ -96,11 +113,11 @@ export function createAiCompletion(options) {
|
|
|
96
113
|
const durationMs = now() - started;
|
|
97
114
|
const reportedTokens = result.usage?.totalTokens;
|
|
98
115
|
const totalTokens = reportedTokens || undefined;
|
|
99
|
-
if (
|
|
116
|
+
if (shares.length && options.usageQuota) {
|
|
100
117
|
// Reported usage settles the reservation; without it, estimate the answer on top of the prompt.
|
|
101
118
|
const settled = totalTokens ?? reserved + estimatePromptTokens(result.text);
|
|
102
119
|
if (settled > reserved)
|
|
103
|
-
|
|
120
|
+
record(settled);
|
|
104
121
|
}
|
|
105
122
|
logger.info(formatCompact({
|
|
106
123
|
op: 'ai_completion',
|
|
@@ -121,6 +138,43 @@ export function createAiCompletion(options) {
|
|
|
121
138
|
},
|
|
122
139
|
});
|
|
123
140
|
}
|
|
141
|
+
function usageShares(input) {
|
|
142
|
+
if (!input.usageShares)
|
|
143
|
+
return input.onBehalfOf ? [{ subject: { ...input.onBehalfOf }, weight: 1 }] : [];
|
|
144
|
+
if (input.onBehalfOf || !input.usageShares.length)
|
|
145
|
+
throw new TypeError('AI completion: choose nonempty usageShares or onBehalfOf');
|
|
146
|
+
const shares = new Map();
|
|
147
|
+
for (const { subject, text } of input.usageShares) {
|
|
148
|
+
if (!subject.userId || typeof text !== 'string' || !text.trim())
|
|
149
|
+
throw new TypeError('AI completion: invalid usage share');
|
|
150
|
+
const weight = Math.max(1, estimatePromptTokens(text));
|
|
151
|
+
const key = JSON.stringify([subject.userId, subject.groupId]);
|
|
152
|
+
const previous = shares.get(key);
|
|
153
|
+
if (previous && previous.subject.owner !== subject.owner)
|
|
154
|
+
throw new TypeError('AI completion: conflicting usage subjects');
|
|
155
|
+
shares.set(key, { subject: { ...subject }, weight: weight + (previous?.weight ?? 0) });
|
|
156
|
+
}
|
|
157
|
+
if (!Number.isFinite([...shares.values()].reduce((sum, share) => sum + share.weight, 0)))
|
|
158
|
+
throw new TypeError('AI completion: invalid total weight');
|
|
159
|
+
return [...shares.values()];
|
|
160
|
+
}
|
|
161
|
+
/** Highest-averages rounding is monotone: settling a larger total never needs to refund a user. */
|
|
162
|
+
function allocateTokens(tokens, weights) {
|
|
163
|
+
const total = weights.reduce((sum, weight) => sum + weight, 0);
|
|
164
|
+
const allocated = weights.map(weight => Math.floor(tokens * (weight / total)));
|
|
165
|
+
let remaining = tokens - allocated.reduce((sum, value) => sum + value, 0);
|
|
166
|
+
while (remaining > 0 && weights.length) {
|
|
167
|
+
let next = 0;
|
|
168
|
+
for (let index = 1; index < weights.length; index++) {
|
|
169
|
+
if (weights[index] / (allocated[index] + 1) > weights[next] / (allocated[next] + 1))
|
|
170
|
+
next = index;
|
|
171
|
+
}
|
|
172
|
+
const amount = Math.min(1, remaining);
|
|
173
|
+
allocated[next] += amount;
|
|
174
|
+
remaining -= amount;
|
|
175
|
+
}
|
|
176
|
+
return allocated;
|
|
177
|
+
}
|
|
124
178
|
function requiredText(value, name) {
|
|
125
179
|
if (typeof value !== 'string' || !value.trim())
|
|
126
180
|
throw new TypeError(`AI completion: ${name} is required`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-completion.js","sourceRoot":"","sources":["../../src/plugin-runtime/ai-completion.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Plain text completion for plugins (#804).\n *\n * Plugins that only need text (summarise a chat, classify a message, rewrite a\n * reply) should not borrow a whole Agent turn: that is slow, and the model gets\n * tools such as file access while it reads untrusted group chat. This port does\n * one completion with **no tools at all** — the request carries no tool\n * definitions, so nothing the model writes can be executed — and reuses the\n * provider resilience chain (retry, backoff, timeout). There is no automatic model\n * fallback: a plugin call must never silently fail over to a pricier model, and no\n * per-binding fallback list exists to opt in to.\n *\n * Untrusted text is rendered as `external_content` data blocks (#726), and a\n * call made on behalf of an IM user counts against that user's / group's usage\n * quota (#727).\n */\nimport { resolveModelCandidates } from '../context/model-resolver.js';\nimport type { AIProvider, ProviderResilienceConfig, TextCompleteResult } from '@zhin.js/ai';\nimport type { AiCompletion, AiCompletionInput, AiCompletionResult } from '@zhin.js/core';\nimport { formatCompact, getLogger } from '@zhin.js/logger';\nimport type { AIService } from '../service.js';\nimport { renderExternalContent } from '../security/trust-level.js';\nimport type { UsageQuota } from '../security/usage-quota.js';\nimport { estimatePromptTokens } from '../prompt/estimate-tokens.js';\n\n/**\n * The contract (types and token) lives in `@zhin.js/core` (#877) so plugins can import it from the\n * `zhin.js` main entry without this package; re-exported here unchanged (same token object and id).\n */\nexport { aiCompletionToken } from '@zhin.js/core';\nexport type {\n AiCompletion,\n AiCompletionInput,\n AiCompletionResult,\n AiCompletionUntrustedInput,\n UsageSubject,\n} from '@zhin.js/core';\n\nconst logger = getLogger('agent');\n\n/** Thrown when the `onBehalfOf` user or group is over its usage quota; `message` is user-facing. Recognise it with `isAiCompletionQuotaError`. */\nexport class AiCompletionQuotaError extends Error {\n override readonly name = 'AiCompletionQuotaError' as const;\n readonly scope: 'user' | 'group';\n readonly retryAfterSeconds: number;\n\n constructor(message: string, scope: 'user' | 'group', retryAfterSeconds: number) {\n super(message);\n this.scope = scope;\n this.retryAfterSeconds = retryAfterSeconds;\n }\n}\n\nexport interface AiCompletionOptions {\n readonly service: Pick<AIService, 'getBindingRegistry' | 'getProvider' | 'getAgentConfig'>\n & Partial<Pick<AIService, 'getModelRegistry'>>;\n readonly usageQuota?: Pick<UsageQuota, 'check' | 'record'>;\n readonly now?: () => number;\n}\n\nexport function createAiCompletion(options: AiCompletionOptions): AiCompletion {\n const now = options.now ?? Date.now;\n return Object.freeze({\n async completeText(input: AiCompletionInput): Promise<AiCompletionResult> {\n const purpose = requiredText(input.purpose, 'purpose');\n const prompt = requiredText(input.prompt, 'prompt');\n const registry = options.service.getBindingRegistry();\n const binding = input.agent ? registry.getBinding(input.agent) : registry.requireZhinBinding();\n if (!binding) throw new Error(`AI completion: agent binding \"${input.agent}\" not found`);\n const provider: AIProvider = options.service.getProvider(binding.providerAlias);\n const model = input.model?.trim() || binding.model || provider.models[0] || '';\n\n if (input.onBehalfOf && options.usageQuota) {\n const decision = options.usageQuota.check(input.onBehalfOf);\n if (!decision.allowed) {\n throw new AiCompletionQuotaError(decision.message, decision.scope, decision.retryAfterSeconds);\n }\n }\n\n const user = [\n prompt,\n ...(input.untrusted ?? []).map(item => renderExternalContent(sourceLabel(item.source), neutralizeBlockMarkers(String(item.text ?? '')))),\n ].join('\\n\\n');\n const opts = {\n model,\n temperature: input.temperature,\n maxTokens: input.maxTokens,\n timeoutMs: input.timeoutMs,\n signal: input.signal,\n // Same candidates as the conversation path (bound model, registry picks, then the\n // provider's models); whether they are tried is up to `providerResilience.fallback`.\n fallbackModels: resolveModelCandidates(\n provider.models,\n options.service.getModelRegistry?.() ?? null,\n binding.providerAlias,\n { chatModel: binding.model },\n 'chat',\n model,\n ).filter(id => id && id !== model),\n resilience: options.service.getAgentConfig()?.providerResilience as ProviderResilienceConfig | undefined,\n };\n // Reserve the prompt estimate before the call: concurrent calls then see each other's\n // spend at `check`, and a call that fails after reaching the provider is still billed.\n const quotaSubject = input.onBehalfOf && options.usageQuota ? input.onBehalfOf : undefined;\n const reserved = quotaSubject ? estimatePromptTokens(`${input.system ?? ''}\\n${user}`) : 0;\n if (quotaSubject && reserved > 0) options.usageQuota!.record(quotaSubject, reserved);\n const started = now();\n let result: TextCompleteResult;\n try {\n result = provider.completeTextResult\n ? await provider.completeTextResult(input.system ?? '', user, opts)\n : { text: await provider.completeText(input.system ?? '', user, opts), model };\n } catch (error) {\n logger.warn(formatCompact({\n op: 'ai_completion',\n purpose,\n provider: binding.providerAlias,\n model,\n outcome: 'error',\n durationMs: now() - started,\n error: error instanceof Error ? error.message : String(error),\n }));\n throw error;\n }\n const durationMs = now() - started;\n const reportedTokens = result.usage?.totalTokens;\n const totalTokens = reportedTokens || undefined;\n if (quotaSubject) {\n // Reported usage settles the reservation; without it, estimate the answer on top of the prompt.\n const settled = totalTokens ?? reserved + estimatePromptTokens(result.text);\n if (settled > reserved) options.usageQuota!.record(quotaSubject, settled - reserved);\n }\n logger.info(formatCompact({\n op: 'ai_completion',\n purpose,\n provider: binding.providerAlias,\n model: result.model,\n outcome: 'ok',\n durationMs,\n ...(totalTokens ? { tokens: totalTokens } : {}),\n untrusted: input.untrusted?.length ?? 0,\n }));\n return Object.freeze({\n text: result.text,\n model: result.model,\n durationMs,\n ...(result.usage ? { usage: result.usage } : {}),\n });\n },\n });\n}\n\nfunction requiredText(value: unknown, name: string): string {\n if (typeof value !== 'string' || !value.trim()) throw new TypeError(`AI completion: ${name} is required`);\n return value;\n}\n\n/** Untrusted text must not be able to close its data block early and continue as instructions. */\nfunction neutralizeBlockMarkers(text: string): string {\n return text.replace(/\\[(\\s*(?:end\\s+)?external_content)/giu, '[$1');\n}\n\n/** Keeps the source label from closing the data block or injecting quotes. */\nfunction sourceLabel(source: unknown): string {\n const text = String(source ?? '').replace(/[^\\p{L}\\p{N}_.:/-]+/gu, '-').slice(0, 64);\n return text || 'untrusted';\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ai-completion.js","sourceRoot":"","sources":["../../src/plugin-runtime/ai-completion.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Plain text completion for plugins (#804).\n *\n * Plugins that only need text (summarise a chat, classify a message, rewrite a\n * reply) should not borrow a whole Agent turn: that is slow, and the model gets\n * tools such as file access while it reads untrusted group chat. This port does\n * one completion with **no tools at all** — the request carries no tool\n * definitions, so nothing the model writes can be executed — and reuses the\n * provider resilience chain (retry, backoff, timeout). There is no automatic model\n * fallback: a plugin call must never silently fail over to a pricier model, and no\n * per-binding fallback list exists to opt in to.\n *\n * Untrusted text is rendered as `external_content` data blocks (#726), and a\n * call made on behalf of an IM user counts against that user's / group's usage\n * quota (#727).\n */\nimport { resolveModelCandidates } from '../context/model-resolver.js';\nimport type { AIProvider, ProviderResilienceConfig, TextCompleteResult } from '@zhin.js/ai';\nimport type { AiCompletion, AiCompletionInput, AiCompletionResult, UsageSubject } from '@zhin.js/core';\nimport { formatCompact, getLogger } from '@zhin.js/logger';\nimport type { AIService } from '../service.js';\nimport { renderExternalContent } from '../security/trust-level.js';\nimport type { UsageQuota } from '../security/usage-quota.js';\nimport { estimatePromptTokens } from '../prompt/estimate-tokens.js';\n\n/**\n * The contract (types and token) lives in `@zhin.js/core` (#877) so plugins can import it from the\n * `zhin.js` main entry without this package; re-exported here unchanged (same token object and id).\n */\nexport { aiCompletionToken } from '@zhin.js/core';\nexport type {\n AiCompletion,\n AiCompletionInput,\n AiCompletionResult,\n AiCompletionUntrustedInput,\n AiCompletionUsageShare,\n UsageSubject,\n} from '@zhin.js/core';\n\nconst logger = getLogger('agent');\n\n/** Thrown when the `onBehalfOf` user or group is over its usage quota; `message` is user-facing. Recognise it with `isAiCompletionQuotaError`. */\nexport class AiCompletionQuotaError extends Error {\n override readonly name = 'AiCompletionQuotaError' as const;\n readonly scope: 'user' | 'group';\n readonly retryAfterSeconds: number;\n readonly deniedUserIds?: readonly string[];\n\n constructor(message: string, scope: 'user' | 'group', retryAfterSeconds: number, deniedUserIds?: readonly string[]) {\n super(message);\n this.scope = scope;\n this.retryAfterSeconds = retryAfterSeconds;\n this.deniedUserIds = deniedUserIds;\n }\n}\n\nexport interface AiCompletionOptions {\n readonly service: Pick<AIService, 'getBindingRegistry' | 'getProvider' | 'getAgentConfig'>\n & Partial<Pick<AIService, 'getModelRegistry'>>;\n readonly usageQuota?: Pick<UsageQuota, 'check' | 'record'> & Partial<Pick<UsageQuota, 'checkBatch'>>;\n readonly now?: () => number;\n}\n\nexport function createAiCompletion(options: AiCompletionOptions): AiCompletion {\n const now = options.now ?? Date.now;\n return Object.freeze({\n ...(options.usageQuota && !options.usageQuota.checkBatch ? {} : { supportsUsageShares: true as const }),\n async completeText(input: AiCompletionInput): Promise<AiCompletionResult> {\n const purpose = requiredText(input.purpose, 'purpose');\n const prompt = requiredText(input.prompt, 'prompt');\n const shares = usageShares(input);\n const registry = options.service.getBindingRegistry();\n const binding = input.agent ? registry.getBinding(input.agent) : registry.requireZhinBinding();\n if (!binding) throw new Error(`AI completion: agent binding \"${input.agent}\" not found`);\n const provider: AIProvider = options.service.getProvider(binding.providerAlias);\n const model = input.model?.trim() || binding.model || provider.models[0] || '';\n\n input.signal?.throwIfAborted();\n if (shares.length && options.usageQuota) {\n if (input.usageShares && !options.usageQuota.checkBatch) throw new Error('AI completion: quota does not support shared attribution');\n const decision = input.usageShares\n ? options.usageQuota.checkBatch!(shares.map(share => share.subject))\n : options.usageQuota.check(shares[0]!.subject);\n if (!decision.allowed) {\n throw new AiCompletionQuotaError(decision.message, decision.scope, decision.retryAfterSeconds,\n 'deniedUserIds' in decision ? decision.deniedUserIds as readonly string[] : undefined);\n }\n }\n\n const user = [\n prompt,\n ...(input.untrusted ?? []).map(item => renderExternalContent(sourceLabel(item.source), neutralizeBlockMarkers(String(item.text ?? '')))),\n ].join('\\n\\n');\n const opts = {\n model,\n temperature: input.temperature,\n maxTokens: input.maxTokens,\n timeoutMs: input.timeoutMs,\n signal: input.signal,\n // Same candidates as the conversation path (bound model, registry picks, then the\n // provider's models); whether they are tried is up to `providerResilience.fallback`.\n fallbackModels: resolveModelCandidates(\n provider.models,\n options.service.getModelRegistry?.() ?? null,\n binding.providerAlias,\n { chatModel: binding.model },\n 'chat',\n model,\n ).filter(id => id && id !== model),\n resilience: options.service.getAgentConfig()?.providerResilience as ProviderResilienceConfig | undefined,\n };\n // Reserve the prompt estimate before the call: concurrent calls then see each other's\n // spend at `check`, and a call that fails after reaching the provider is still billed.\n const reserved = shares.length && options.usageQuota ? estimatePromptTokens(`${input.system ?? ''}\\n${user}`) : 0;\n let billed = shares.map(() => 0);\n const record = (tokens: number) => {\n if (!options.usageQuota || tokens <= 0) return;\n const allocated = allocateTokens(tokens, shares.map(share => share.weight));\n shares.forEach((share, index) => {\n options.usageQuota!.record(share.subject, allocated[index]! - billed[index]!);\n });\n billed = allocated;\n };\n record(reserved);\n const started = now();\n let result: TextCompleteResult;\n try {\n result = provider.completeTextResult\n ? await provider.completeTextResult(input.system ?? '', user, opts)\n : { text: await provider.completeText(input.system ?? '', user, opts), model };\n } catch (error) {\n logger.warn(formatCompact({\n op: 'ai_completion',\n purpose,\n provider: binding.providerAlias,\n model,\n outcome: 'error',\n durationMs: now() - started,\n error: error instanceof Error ? error.message : String(error),\n }));\n throw error;\n }\n const durationMs = now() - started;\n const reportedTokens = result.usage?.totalTokens;\n const totalTokens = reportedTokens || undefined;\n if (shares.length && options.usageQuota) {\n // Reported usage settles the reservation; without it, estimate the answer on top of the prompt.\n const settled = totalTokens ?? reserved + estimatePromptTokens(result.text);\n if (settled > reserved) record(settled);\n }\n logger.info(formatCompact({\n op: 'ai_completion',\n purpose,\n provider: binding.providerAlias,\n model: result.model,\n outcome: 'ok',\n durationMs,\n ...(totalTokens ? { tokens: totalTokens } : {}),\n untrusted: input.untrusted?.length ?? 0,\n }));\n return Object.freeze({\n text: result.text,\n model: result.model,\n durationMs,\n ...(result.usage ? { usage: result.usage } : {}),\n });\n },\n });\n}\n\nfunction usageShares(input: AiCompletionInput): readonly { subject: UsageSubject; weight: number }[] {\n if (!input.usageShares) return input.onBehalfOf ? [{ subject: { ...input.onBehalfOf }, weight: 1 }] : [];\n if (input.onBehalfOf || !input.usageShares.length) throw new TypeError('AI completion: choose nonempty usageShares or onBehalfOf');\n const shares = new Map<string, { subject: UsageSubject; weight: number }>();\n for (const { subject, text } of input.usageShares) {\n if (!subject.userId || typeof text !== 'string' || !text.trim()) throw new TypeError('AI completion: invalid usage share');\n const weight = Math.max(1, estimatePromptTokens(text));\n const key = JSON.stringify([subject.userId, subject.groupId]);\n const previous = shares.get(key);\n if (previous && previous.subject.owner !== subject.owner) throw new TypeError('AI completion: conflicting usage subjects');\n shares.set(key, { subject: { ...subject }, weight: weight + (previous?.weight ?? 0) });\n }\n if (!Number.isFinite([...shares.values()].reduce((sum, share) => sum + share.weight, 0))) throw new TypeError('AI completion: invalid total weight');\n return [...shares.values()];\n}\n\n/** Highest-averages rounding is monotone: settling a larger total never needs to refund a user. */\nfunction allocateTokens(tokens: number, weights: readonly number[]): number[] {\n const total = weights.reduce((sum, weight) => sum + weight, 0);\n const allocated = weights.map(weight => Math.floor(tokens * (weight / total)));\n let remaining = tokens - allocated.reduce((sum, value) => sum + value, 0);\n while (remaining > 0 && weights.length) {\n let next = 0;\n for (let index = 1; index < weights.length; index++) {\n if (weights[index]! / (allocated[index]! + 1) > weights[next]! / (allocated[next]! + 1)) next = index;\n }\n const amount = Math.min(1, remaining);\n allocated[next]! += amount; remaining -= amount;\n }\n return allocated;\n}\n\nfunction requiredText(value: unknown, name: string): string {\n if (typeof value !== 'string' || !value.trim()) throw new TypeError(`AI completion: ${name} is required`);\n return value;\n}\n\n/** Untrusted text must not be able to close its data block early and continue as instructions. */\nfunction neutralizeBlockMarkers(text: string): string {\n return text.replace(/\\[(\\s*(?:end\\s+)?external_content)/giu, '[$1');\n}\n\n/** Keeps the source label from closing the data block or injecting quotes. */\nfunction sourceLabel(source: unknown): string {\n const text = String(source ?? '').replace(/[^\\p{L}\\p{N}_.:/-]+/gu, '-').slice(0, 64);\n return text || 'untrusted';\n}\n"]}
|
|
@@ -36,7 +36,9 @@ export class CapabilityIngress {
|
|
|
36
36
|
mcp: bindMcp(mcp, owner, isActive),
|
|
37
37
|
promptSections: Object.freeze([...(promptSections?.visible(owner, promptProfile) ?? [])]
|
|
38
38
|
.filter((section) => !section.platforms
|
|
39
|
-
|| (turn?.origin.kind === 'im' && section.platforms.includes(turn.origin.platform)))
|
|
39
|
+
|| (turn?.origin.kind === 'im' && section.platforms.includes(turn.origin.platform)))
|
|
40
|
+
.filter((section) => !section.scopes
|
|
41
|
+
|| (turn?.origin.kind === 'im' && section.scopes.includes(turn.origin.scope)))),
|
|
40
42
|
});
|
|
41
43
|
}
|
|
42
44
|
}
|