@pikku/core 0.12.80 → 0.12.83
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/CHANGELOG.md +345 -0
- package/dist/errors/index.d.ts +1 -1
- package/dist/errors/index.js +1 -1
- package/dist/function/function-runner.js +2 -5
- package/dist/function/index.d.ts +1 -1
- package/dist/index.d.ts +11 -11
- package/dist/index.js +3 -3
- package/dist/pikku-state.js +4 -0
- package/dist/services/ai-agent-runner-service.d.ts +7 -0
- package/dist/services/ai-run-state-service.d.ts +10 -0
- package/dist/services/in-memory-ai-run-state-service.d.ts +5 -1
- package/dist/services/in-memory-ai-run-state-service.js +9 -0
- package/dist/services/index.d.ts +15 -16
- package/dist/services/index.js +5 -5
- package/dist/services/meta-service.d.ts +2 -1
- package/dist/services/scoped-credential-service.d.ts +21 -0
- package/dist/services/scoped-credential-service.js +53 -0
- package/dist/testing/service-tests/ai-storage-service-tests.js +76 -0
- package/dist/types/core.types.d.ts +2 -3
- package/dist/types/state.types.d.ts +19 -1
- package/dist/wirings/actor-flow/index.d.ts +1 -1
- package/dist/wirings/ai-agent/ai-agent-finalize.d.ts +58 -0
- package/dist/wirings/ai-agent/ai-agent-finalize.js +138 -0
- package/dist/wirings/ai-agent/ai-agent-interrupt.js +1 -0
- package/dist/wirings/ai-agent/ai-agent-memory.d.ts +2 -8
- package/dist/wirings/ai-agent/ai-agent-memory.js +34 -17
- package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +7 -0
- package/dist/wirings/ai-agent/ai-agent-model-config.js +44 -1
- package/dist/wirings/ai-agent/ai-agent-prepare.js +4 -0
- package/dist/wirings/ai-agent/ai-agent-runner.js +61 -40
- package/dist/wirings/ai-agent/ai-agent-stream.js +89 -36
- package/dist/wirings/ai-agent/ai-agent-turn.d.ts +1 -0
- package/dist/wirings/ai-agent/ai-agent-turn.js +1 -0
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +46 -1
- package/dist/wirings/ai-agent/index.d.ts +8 -7
- package/dist/wirings/ai-agent/index.js +5 -4
- package/dist/wirings/ai-scorer/ai-scorer-grade.d.ts +26 -0
- package/dist/wirings/ai-scorer/ai-scorer-grade.js +33 -0
- package/dist/wirings/ai-scorer/ai-scorer-judge.d.ts +17 -0
- package/dist/wirings/ai-scorer/ai-scorer-judge.js +92 -0
- package/dist/wirings/ai-scorer/ai-scorer-live.d.ts +15 -0
- package/dist/wirings/ai-scorer/ai-scorer-live.js +38 -0
- package/dist/wirings/ai-scorer/ai-scorer-registry.d.ts +18 -0
- package/dist/wirings/ai-scorer/ai-scorer-registry.js +46 -0
- package/dist/wirings/ai-scorer/ai-scorer-sampling.d.ts +8 -0
- package/dist/wirings/ai-scorer/ai-scorer-sampling.js +31 -0
- package/dist/wirings/ai-scorer/ai-scorer-snapshots.d.ts +10 -0
- package/dist/wirings/ai-scorer/ai-scorer-snapshots.js +40 -0
- package/dist/wirings/ai-scorer/ai-scorer-worker.d.ts +15 -0
- package/dist/wirings/ai-scorer/ai-scorer-worker.js +58 -0
- package/dist/wirings/ai-scorer/ai-scorer.d.ts +39 -0
- package/dist/wirings/ai-scorer/ai-scorer.js +40 -0
- package/dist/wirings/ai-scorer/ai-scorer.types.d.ts +90 -0
- package/dist/wirings/ai-scorer/ai-scorer.types.js +4 -0
- package/dist/wirings/ai-scorer/index.d.ts +6 -0
- package/dist/wirings/ai-scorer/index.js +5 -0
- package/dist/wirings/channel/index.d.ts +5 -6
- package/dist/wirings/channel/index.js +3 -4
- package/dist/wirings/channel/local/local-channel-runner.js +8 -1
- package/dist/wirings/cli/channel/cli-raw-channel-runner.js +9 -1
- package/dist/wirings/cli/channel/index.d.ts +1 -2
- package/dist/wirings/cli/channel/index.js +0 -1
- package/dist/wirings/cli/cli-runner.js +13 -1
- package/dist/wirings/credential/index.d.ts +1 -1
- package/dist/wirings/gateway/index.d.ts +1 -1
- package/dist/wirings/http/http-runner.js +8 -2
- package/dist/wirings/http/index.d.ts +1 -2
- package/dist/wirings/mcp/index.d.ts +1 -1
- package/dist/wirings/mcp/mcp-runner.d.ts +15 -0
- package/dist/wirings/mcp/mcp-runner.js +18 -5
- package/dist/wirings/persona/index.d.ts +3 -4
- package/dist/wirings/persona/index.js +2 -3
- package/dist/wirings/queue/index.d.ts +1 -3
- package/dist/wirings/queue/index.js +1 -3
- package/dist/wirings/rpc/addon-runner.d.ts +8 -0
- package/dist/wirings/rpc/addon-runner.js +31 -3
- package/dist/wirings/rpc/rpc-runner.js +4 -0
- package/dist/wirings/rpc/rpc-types.d.ts +8 -0
- package/dist/wirings/rpc/wire-addon.d.ts +25 -0
- package/dist/wirings/rpc/wire-addon.js +8 -0
- package/dist/wirings/scheduler/index.d.ts +1 -1
- package/dist/wirings/trigger/index.d.ts +1 -1
- package/dist/wirings/virtual-user/index.d.ts +5 -6
- package/dist/wirings/virtual-user/index.js +2 -4
- package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +85 -15
- package/dist/wirings/workflow/feature.d.ts +2 -1
- package/dist/wirings/workflow/index.d.ts +5 -16
- package/dist/wirings/workflow/index.js +1 -9
- package/dist/wirings/workflow/pikku-scenario-service.d.ts +17 -7
- package/dist/wirings/workflow/pikku-scenario-service.js +48 -13
- package/dist/wirings/workflow/pikku-workflow-service.js +17 -3
- package/dist/wirings/workflow/scenario-step.types.d.ts +8 -0
- package/dist/wirings/workflow/scenario.types.d.ts +37 -0
- package/dist/wirings/workflow/workflow-approval-audit.d.ts +16 -0
- package/dist/wirings/workflow/workflow-approval-audit.js +40 -0
- package/dist/wirings/workflow/workflow-approval-policy.d.ts +20 -0
- package/dist/wirings/workflow/workflow-approval-policy.js +48 -0
- package/dist/wirings/workflow/workflow-approval.d.ts +29 -1
- package/dist/wirings/workflow/workflow-approval.js +65 -2
- package/dist/wirings/workflow/workflow-run-ownership.d.ts +2 -1
- package/dist/wirings/workflow/workflow-run-ownership.js +2 -1
- package/dist/wirings/workflow/workflow.types.d.ts +2 -37
- package/knowledge/decisions/internals/addon-pikku-meta-ships-at-the-package-root-or-under-dist.md +32 -0
- package/knowledge/decisions/internals/an-addon-scope-root-loses-to-a-root-the-host-already-declares.md +39 -0
- package/knowledge/decisions/internals/index.md +30 -3
- package/knowledge/decisions/internals/validate-runs-checks-by-precondition.md +115 -0
- package/knowledge/decisions/security/a-function-never-receives-the-secret-service.md +37 -0
- package/knowledge/decisions/security/a-workflow-run-is-read-and-approved-by-its-owner.md +30 -14
- package/knowledge/decisions/security/an-approval-answer-outlives-the-run-it-answered.md +59 -0
- package/knowledge/decisions/security/index.md +3 -1
- package/knowledge/questions/index.md +1 -1
- package/package.json +3 -2
- package/scripts/generate-api-report.mts +143 -18
- package/src/api-report.test.ts +2 -2
- package/src/errors/index.ts +1 -1
- package/src/function/function-runner.test.ts +52 -0
- package/src/function/function-runner.ts +5 -9
- package/src/function/index.ts +0 -2
- package/src/index.ts +0 -35
- package/src/pikku-state.ts +5 -0
- package/src/public-surface.json +81 -118
- package/src/services/ai-agent-runner-service.ts +12 -1
- package/src/services/ai-run-state-service.ts +11 -0
- package/src/services/in-memory-ai-run-state-service.ts +13 -0
- package/src/services/index.ts +7 -58
- package/src/services/meta-service.ts +2 -4
- package/src/services/scoped-credential-service.test.ts +86 -0
- package/src/services/scoped-credential-service.ts +63 -0
- package/src/testing/service-tests/ai-storage-service-tests.ts +93 -0
- package/src/types/core.types.ts +4 -7
- package/src/types/state.types.ts +21 -1
- package/src/wirings/actor-flow/index.ts +0 -3
- package/src/wirings/ai-agent/ai-agent-finalize.test.ts +186 -0
- package/src/wirings/ai-agent/ai-agent-finalize.ts +197 -0
- package/src/wirings/ai-agent/ai-agent-interrupt.ts +1 -0
- package/src/wirings/ai-agent/ai-agent-memory.ts +54 -38
- package/src/wirings/ai-agent/ai-agent-model-config.test.ts +72 -3
- package/src/wirings/ai-agent/ai-agent-model-config.ts +49 -1
- package/src/wirings/ai-agent/ai-agent-prepare.ts +4 -0
- package/src/wirings/ai-agent/ai-agent-runner.ts +71 -40
- package/src/wirings/ai-agent/ai-agent-stream-output-hooks.test.ts +353 -0
- package/src/wirings/ai-agent/ai-agent-stream.ts +116 -54
- package/src/wirings/ai-agent/ai-agent-turn.test.ts +67 -0
- package/src/wirings/ai-agent/ai-agent-turn.ts +1 -0
- package/src/wirings/ai-agent/ai-agent.types.ts +64 -4
- package/src/wirings/ai-agent/index.ts +2 -16
- package/src/wirings/ai-scorer/ai-scorer-grade.test.ts +106 -0
- package/src/wirings/ai-scorer/ai-scorer-grade.ts +55 -0
- package/src/wirings/ai-scorer/ai-scorer-judge.test.ts +143 -0
- package/src/wirings/ai-scorer/ai-scorer-judge.ts +120 -0
- package/src/wirings/ai-scorer/ai-scorer-live.test.ts +174 -0
- package/src/wirings/ai-scorer/ai-scorer-live.ts +56 -0
- package/src/wirings/ai-scorer/ai-scorer-registry.ts +63 -0
- package/src/wirings/ai-scorer/ai-scorer-sampling.test.ts +34 -0
- package/src/wirings/ai-scorer/ai-scorer-sampling.ts +36 -0
- package/src/wirings/ai-scorer/ai-scorer-snapshots.test.ts +49 -0
- package/src/wirings/ai-scorer/ai-scorer-snapshots.ts +46 -0
- package/src/wirings/ai-scorer/ai-scorer-worker.test.ts +122 -0
- package/src/wirings/ai-scorer/ai-scorer-worker.ts +69 -0
- package/src/wirings/ai-scorer/ai-scorer.ts +76 -0
- package/src/wirings/ai-scorer/ai-scorer.types.ts +107 -0
- package/src/wirings/ai-scorer/index.ts +24 -0
- package/src/wirings/channel/index.ts +1 -20
- package/src/wirings/channel/local/local-channel-runner.test.ts +68 -0
- package/src/wirings/channel/local/local-channel-runner.ts +8 -1
- package/src/wirings/cli/channel/cli-raw-channel-runner.test.ts +23 -0
- package/src/wirings/cli/channel/cli-raw-channel-runner.ts +12 -1
- package/src/wirings/cli/channel/index.ts +0 -7
- package/src/wirings/cli/cli-runner.test.ts +68 -0
- package/src/wirings/cli/cli-runner.ts +18 -1
- package/src/wirings/credential/index.ts +0 -1
- package/src/wirings/gateway/index.ts +0 -3
- package/src/wirings/http/http-runner.test.ts +66 -0
- package/src/wirings/http/http-runner.ts +10 -2
- package/src/wirings/http/index.ts +1 -1
- package/src/wirings/mcp/index.ts +0 -1
- package/src/wirings/mcp/mcp-runner.test.ts +181 -0
- package/src/wirings/mcp/mcp-runner.ts +35 -5
- package/src/wirings/persona/index.ts +0 -8
- package/src/wirings/queue/index.ts +0 -14
- package/src/wirings/rpc/addon-runner.ts +62 -3
- package/src/wirings/rpc/addon-secrets.test.ts +391 -0
- package/src/wirings/rpc/rpc-runner.test.ts +2 -0
- package/src/wirings/rpc/rpc-runner.ts +4 -0
- package/src/wirings/rpc/rpc-types.ts +8 -0
- package/src/wirings/rpc/wire-addon.ts +33 -0
- package/src/wirings/scheduler/index.ts +0 -1
- package/src/wirings/trigger/index.ts +0 -1
- package/src/wirings/virtual-user/index.ts +0 -16
- package/src/wirings/workflow/dsl/workflow-dsl.types.ts +96 -16
- package/src/wirings/workflow/feature.ts +2 -5
- package/src/wirings/workflow/graph/graph-runner.test.ts +72 -0
- package/src/wirings/workflow/index.ts +2 -68
- package/src/wirings/workflow/pikku-scenario-service.ts +81 -16
- package/src/wirings/workflow/pikku-workflow-service.test.ts +13 -12
- package/src/wirings/workflow/pikku-workflow-service.ts +28 -4
- package/src/wirings/workflow/scenario-expectations.test.ts +75 -0
- package/src/wirings/workflow/scenario-hooks.test.ts +3 -2
- package/src/wirings/workflow/scenario-step.types.ts +8 -0
- package/src/wirings/workflow/scenario.types.ts +63 -0
- package/src/wirings/workflow/workflow-approval-audit.ts +47 -0
- package/src/wirings/workflow/workflow-approval-policy.test.ts +524 -0
- package/src/wirings/workflow/workflow-approval-policy.ts +68 -0
- package/src/wirings/workflow/workflow-approval.ts +113 -9
- package/src/wirings/workflow/workflow-run-authority.test.ts +12 -15
- package/src/wirings/workflow/workflow-run-ownership.ts +2 -1
- package/src/wirings/workflow/workflow.types.ts +1 -63
- package/src/wirings-stay-decoupled.test.ts +6 -2
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/internal.d.ts +0 -3
- package/dist/internal.js +0 -2
- package/dist/middleware/timeout.d.ts +0 -9
- package/dist/middleware/timeout.js +0 -15
- package/dist/pikku-response.d.ts +0 -6
- package/dist/pikku-response.js +0 -6
- package/dist/services/gopass-secrets.d.ts +0 -15
- package/dist/services/gopass-secrets.js +0 -76
- package/dist/services/http-scenario-actors.d.ts +0 -75
- package/dist/services/http-scenario-actors.js +0 -195
- package/dist/services/http-user-flow-actors.d.ts +0 -67
- package/dist/services/http-user-flow-actors.js +0 -193
- package/dist/services/scenario-actors-service.d.ts +0 -127
- package/dist/services/scenario-actors-service.js +0 -40
- package/dist/services/user-flow-actors-service.d.ts +0 -39
- package/dist/wirings/credential/wire-credential.d.ts +0 -48
- package/dist/wirings/credential/wire-credential.js +0 -47
- package/dist/wirings/oauth2/oauth2-client.d.ts +0 -47
- package/dist/wirings/oauth2/oauth2-client.js +0 -263
- package/dist/wirings/oauth2/oauth2-routes.d.ts +0 -35
- package/dist/wirings/oauth2/oauth2-routes.js +0 -146
- package/dist/wirings/scope/wire-scope.d.ts +0 -33
- package/dist/wirings/scope/wire-scope.js +0 -32
- package/dist/wirings/workflow/dsl/index.d.ts +0 -5
- package/dist/wirings/workflow/dsl/index.js +0 -4
- package/dist/wirings/workflow/graph/index.d.ts +0 -5
- package/dist/wirings/workflow/graph/index.js +0 -4
- /package/dist/{services/user-flow-actors-service.js → wirings/workflow/scenario.types.js} +0 -0
|
@@ -1,7 +1,50 @@
|
|
|
1
1
|
// knowledge: decisions/internals/ai-agent-model-config-stays-a-single-resolution-seam.md
|
|
2
|
+
import { pikkuState } from '../../pikku-state.js';
|
|
3
|
+
const isProviderQualified = (model) => model.includes('/');
|
|
4
|
+
/** `PIKKU_MODEL_ALIASES=cheap:openai/gpt-5-mini,tool:anthropic/claude-sonnet-5` */
|
|
5
|
+
const envAliases = () => {
|
|
6
|
+
const raw = process.env.PIKKU_MODEL_ALIASES;
|
|
7
|
+
if (!raw)
|
|
8
|
+
return {};
|
|
9
|
+
const aliases = {};
|
|
10
|
+
for (const entry of raw.split(',')) {
|
|
11
|
+
// First colon only — a model id may contain its own.
|
|
12
|
+
const separator = entry.indexOf(':');
|
|
13
|
+
if (separator === -1)
|
|
14
|
+
continue;
|
|
15
|
+
const alias = entry.slice(0, separator).trim();
|
|
16
|
+
const model = entry.slice(separator + 1).trim();
|
|
17
|
+
if (alias && model)
|
|
18
|
+
aliases[alias] = model;
|
|
19
|
+
}
|
|
20
|
+
return aliases;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Resolves a model name to a concrete `provider/model`. Aliases come from the
|
|
24
|
+
* `models` table in pikku.config.json; a name containing `/` is already
|
|
25
|
+
* concrete. Read from the main package, not the calling addon's — which model
|
|
26
|
+
* a tier points at is the hosting app's decision.
|
|
27
|
+
*/
|
|
28
|
+
export const resolveModelAlias = (model) => {
|
|
29
|
+
if (isProviderQualified(model))
|
|
30
|
+
return model;
|
|
31
|
+
const generated = pikkuState(null, 'agent', 'modelAliases');
|
|
32
|
+
const override = envAliases()[model];
|
|
33
|
+
const resolved = override ?? generated[model];
|
|
34
|
+
if (!resolved) {
|
|
35
|
+
const known = Object.keys({ ...generated, ...envAliases() }).sort();
|
|
36
|
+
throw new Error(`Unknown model alias '${model}'. ` +
|
|
37
|
+
(known.length
|
|
38
|
+
? `Known aliases: ${known.join(', ')}. `
|
|
39
|
+
: `No aliases are configured. `) +
|
|
40
|
+
`Add it to the "models" table in pikku.config.json, or name a ` +
|
|
41
|
+
`provider-qualified model such as 'openai/gpt-5-mini'.`);
|
|
42
|
+
}
|
|
43
|
+
return resolved;
|
|
44
|
+
};
|
|
2
45
|
export function resolveModelConfig(_agentName, agent) {
|
|
3
46
|
return {
|
|
4
|
-
model: agent.model,
|
|
47
|
+
model: resolveModelAlias(agent.model),
|
|
5
48
|
temperature: agent.temperature,
|
|
6
49
|
maxSteps: agent.maxSteps,
|
|
7
50
|
};
|
|
@@ -357,6 +357,10 @@ export async function buildToolDefs(params, agentSessionMap, resourceId, agentNa
|
|
|
357
357
|
secretOverrides: capturedAddonConfig?.secretOverrides,
|
|
358
358
|
variableOverrides: capturedAddonConfig?.variableOverrides,
|
|
359
359
|
credentialOverrides: capturedAddonConfig?.credentialOverrides,
|
|
360
|
+
secretGrants: capturedAddonConfig?.secretGrants,
|
|
361
|
+
credentialGrants: capturedAddonConfig?.credentialGrants,
|
|
362
|
+
globalSecrets: capturedAddonConfig?.globalSecrets,
|
|
363
|
+
globalCredentials: capturedAddonConfig?.globalCredentials,
|
|
360
364
|
}
|
|
361
365
|
: undefined;
|
|
362
366
|
services = await getOrCreatePackageSingletonServices(capturedPkg, singletonServices, addonInstance);
|
|
@@ -4,6 +4,7 @@ import { checkForApprovals, appendStepMessages } from './ai-agent-stream.js';
|
|
|
4
4
|
import { AgentInterruptedError, isAbortError, persistOrphanedToolResults, registerInterruptibleRun, trackInterruptNote, trackToolExecution, } from './ai-agent-interrupt.js';
|
|
5
5
|
import { pikkuState, getSingletonServices } from '../../pikku-state.js';
|
|
6
6
|
import { applyInputMiddleware, describeApprovals, notifyAfterStep, toAccumulatedStep, } from './ai-agent-turn.js';
|
|
7
|
+
import { applyOutputMiddleware, finalizeAgentRun, lastUserMessageText, } from './ai-agent-finalize.js';
|
|
7
8
|
import { resolveModelConfig } from './ai-agent-model-config.js';
|
|
8
9
|
import { AIProviderNotConfiguredError } from '../../errors/errors.js';
|
|
9
10
|
import { randomUUID } from './ai-agent-utils.js';
|
|
@@ -192,27 +193,25 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
|
|
|
192
193
|
text: finalText,
|
|
193
194
|
steps: accumulatedSteps,
|
|
194
195
|
};
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
text: outputText,
|
|
202
|
-
messages: outputMessages,
|
|
203
|
-
usage: totalUsage,
|
|
204
|
-
});
|
|
205
|
-
outputText = modResult.text;
|
|
206
|
-
outputMessages = modResult.messages;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
196
|
+
const { text: outputText, steps: outputSteps } = await applyOutputMiddleware(aiMiddlewares, singletonServices, {
|
|
197
|
+
text: finalText,
|
|
198
|
+
messages: runnerParams.messages,
|
|
199
|
+
steps: result.steps,
|
|
200
|
+
usage: totalUsage,
|
|
201
|
+
});
|
|
209
202
|
await saveMessages(storage, threadId, input.resourceId, memoryConfig, persistedUserMessage, {
|
|
210
|
-
...result,
|
|
211
203
|
text: outputText,
|
|
204
|
+
steps: outputSteps,
|
|
212
205
|
uiSpec: structuredOutput.uiSpec,
|
|
213
206
|
});
|
|
214
|
-
await aiRunState
|
|
215
|
-
|
|
207
|
+
await finalizeAgentRun(aiRunState, {
|
|
208
|
+
runId,
|
|
209
|
+
agentName,
|
|
210
|
+
threadId,
|
|
211
|
+
resourceId: input.resourceId,
|
|
212
|
+
input: lastUserMessageText(runnerParams.messages),
|
|
213
|
+
text: outputText,
|
|
214
|
+
steps: outputSteps,
|
|
216
215
|
usage: { ...totalUsage, model: agent.model },
|
|
217
216
|
});
|
|
218
217
|
return {
|
|
@@ -220,7 +219,7 @@ export async function runAIAgent(agentName, input, params, agentSessionMap) {
|
|
|
220
219
|
text: outputText,
|
|
221
220
|
object: finalObject,
|
|
222
221
|
threadId,
|
|
223
|
-
steps:
|
|
222
|
+
steps: outputSteps,
|
|
224
223
|
usage: totalUsage,
|
|
225
224
|
};
|
|
226
225
|
}
|
|
@@ -305,6 +304,7 @@ export async function resumeAIAgentSync(runId, approvals, params, expectedAgentN
|
|
|
305
304
|
if (!claimedIds.has(toolCallId))
|
|
306
305
|
continue;
|
|
307
306
|
let resultStr;
|
|
307
|
+
let toolError;
|
|
308
308
|
if (rejectedIds.has(toolCallId)) {
|
|
309
309
|
resultStr =
|
|
310
310
|
'The user explicitly declined this action. Inform them that it was declined and do not retry.';
|
|
@@ -330,7 +330,8 @@ export async function resumeAIAgentSync(runId, approvals, params, expectedAgentN
|
|
|
330
330
|
resultStr = JSON.stringify(err.payload);
|
|
331
331
|
}
|
|
332
332
|
else {
|
|
333
|
-
|
|
333
|
+
toolError = err instanceof Error ? err.message : String(err);
|
|
334
|
+
resultStr = `Error: ${toolError}`;
|
|
334
335
|
}
|
|
335
336
|
}
|
|
336
337
|
}
|
|
@@ -344,6 +345,7 @@ export async function resumeAIAgentSync(runId, approvals, params, expectedAgentN
|
|
|
344
345
|
? JSON.parse(pending.args)
|
|
345
346
|
: pending.args,
|
|
346
347
|
result: resultStr,
|
|
348
|
+
...(toolError ? { error: toolError } : {}),
|
|
347
349
|
});
|
|
348
350
|
}
|
|
349
351
|
if (storage && toolCallMessages.length > 0) {
|
|
@@ -361,9 +363,23 @@ export async function resumeAIAgentSync(runId, approvals, params, expectedAgentN
|
|
|
361
363
|
]);
|
|
362
364
|
}
|
|
363
365
|
await aiRunState.updateRun(runId, { status: 'running' });
|
|
364
|
-
return continueAfterToolResultSync(run, agent, packageName, resolvedName, storage, memoryConfig, agentRunner, params, aiRunState
|
|
366
|
+
return continueAfterToolResultSync(run, agent, packageName, resolvedName, storage, memoryConfig, agentRunner, params, aiRunState,
|
|
367
|
+
// The approved tools were executed here, before the model was re-entered,
|
|
368
|
+
// so they belong to the run's step record — otherwise a tool that failed
|
|
369
|
+
// after approval leaves no trace on the run at all.
|
|
370
|
+
toolCallMessages.length > 0
|
|
371
|
+
? {
|
|
372
|
+
usage: { inputTokens: 0, outputTokens: 0 },
|
|
373
|
+
toolCalls: toolCallMessages.map((tc) => ({
|
|
374
|
+
name: tc.toolName,
|
|
375
|
+
args: (tc.args ?? {}),
|
|
376
|
+
result: tc.result,
|
|
377
|
+
...(tc.error ? { error: tc.error } : {}),
|
|
378
|
+
})),
|
|
379
|
+
}
|
|
380
|
+
: undefined);
|
|
365
381
|
}
|
|
366
|
-
async function continueAfterToolResultSync(run, agent, packageName, resolvedName, storage, memoryConfig, agentRunner, params, aiRunState) {
|
|
382
|
+
async function continueAfterToolResultSync(run, agent, packageName, resolvedName, storage, memoryConfig, agentRunner, params, aiRunState, resumedToolStep) {
|
|
367
383
|
const singletonServices = getSingletonServices();
|
|
368
384
|
const agentsMeta = pikkuState(packageName, 'agent', 'agentsMeta');
|
|
369
385
|
const meta = agentsMeta[resolvedName];
|
|
@@ -416,6 +432,11 @@ async function continueAfterToolResultSync(run, agent, packageName, resolvedName
|
|
|
416
432
|
runnerParams.abortSignal = interruptHandle.signal;
|
|
417
433
|
runnerParams.tools = trackToolExecution(runnerParams.tools, interruptHandle);
|
|
418
434
|
try {
|
|
435
|
+
// Kept out of `accumulatedSteps` deliberately: that array drives
|
|
436
|
+
// `saveMessages`, and the approved tool's messages were already written to
|
|
437
|
+
// the thread before the model was re-entered. It belongs to the run's step
|
|
438
|
+
// record, not to persistence.
|
|
439
|
+
const withResumedStep = (steps) => resumedToolStep ? [resumedToolStep, ...steps] : steps;
|
|
419
440
|
const accumulatedSteps = [];
|
|
420
441
|
const totalUsage = { inputTokens: 0, outputTokens: 0 };
|
|
421
442
|
let lastStepResult = null;
|
|
@@ -475,7 +496,7 @@ async function continueAfterToolResultSync(run, agent, packageName, resolvedName
|
|
|
475
496
|
runId: run.runId,
|
|
476
497
|
text: suspendedText,
|
|
477
498
|
threadId: run.threadId,
|
|
478
|
-
steps: accumulatedSteps,
|
|
499
|
+
steps: withResumedStep(accumulatedSteps),
|
|
479
500
|
usage: totalUsage,
|
|
480
501
|
status: 'suspended',
|
|
481
502
|
pendingApprovals: approvalsNeeded.map((a) => ({
|
|
@@ -495,26 +516,26 @@ async function continueAfterToolResultSync(run, agent, packageName, resolvedName
|
|
|
495
516
|
text: finalText,
|
|
496
517
|
steps: accumulatedSteps,
|
|
497
518
|
};
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
text: outputText,
|
|
505
|
-
messages: outputMessages,
|
|
506
|
-
usage: totalUsage,
|
|
507
|
-
});
|
|
508
|
-
outputText = modResult.text;
|
|
509
|
-
outputMessages = modResult.messages;
|
|
510
|
-
}
|
|
511
|
-
}
|
|
519
|
+
const { text: outputText, steps: outputSteps } = await applyOutputMiddleware(aiMiddlewares, singletonServices, {
|
|
520
|
+
text: finalText,
|
|
521
|
+
messages: runnerParams.messages,
|
|
522
|
+
steps: withResumedStep(result.steps),
|
|
523
|
+
usage: totalUsage,
|
|
524
|
+
});
|
|
512
525
|
await saveMessages(storage, run.threadId, run.resourceId, memoryConfig, null, {
|
|
513
|
-
...result,
|
|
514
526
|
text: outputText,
|
|
527
|
+
// The approved tool's messages were written before the model was
|
|
528
|
+
// re-entered, so only the steps this leg generated are persisted here.
|
|
529
|
+
steps: accumulatedSteps,
|
|
515
530
|
});
|
|
516
|
-
await aiRunState
|
|
517
|
-
|
|
531
|
+
await finalizeAgentRun(aiRunState, {
|
|
532
|
+
runId: run.runId,
|
|
533
|
+
agentName: resolvedName,
|
|
534
|
+
threadId: run.threadId,
|
|
535
|
+
resourceId: run.resourceId,
|
|
536
|
+
input: lastUserMessageText(runnerParams.messages),
|
|
537
|
+
text: outputText,
|
|
538
|
+
steps: outputSteps,
|
|
518
539
|
usage: { ...totalUsage, model: agent.model },
|
|
519
540
|
});
|
|
520
541
|
return {
|
|
@@ -522,7 +543,7 @@ async function continueAfterToolResultSync(run, agent, packageName, resolvedName
|
|
|
522
543
|
text: outputText,
|
|
523
544
|
object: finalObject,
|
|
524
545
|
threadId: run.threadId,
|
|
525
|
-
steps:
|
|
546
|
+
steps: outputSteps,
|
|
526
547
|
usage: totalUsage,
|
|
527
548
|
};
|
|
528
549
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { finalizeAgentRun, lastUserMessageText, } from './ai-agent-finalize.js';
|
|
1
2
|
import { pikkuState, getSingletonServices } from '../../pikku-state.js';
|
|
2
3
|
import { applyInputMiddleware } from './ai-agent-turn.js';
|
|
3
4
|
import { AIProviderNotConfiguredError } from '../../errors/errors.js';
|
|
@@ -18,6 +19,9 @@ function createPersistingChannel(parent, storage, threadId, logger) {
|
|
|
18
19
|
inputTokens: 0,
|
|
19
20
|
outputTokens: 0,
|
|
20
21
|
};
|
|
22
|
+
// Survives the per-step flush below, which clears its own buffers: the run
|
|
23
|
+
// record needs every call the run made, not just the last step's.
|
|
24
|
+
const runToolCalls = [];
|
|
21
25
|
const flushStep = async (opts) => {
|
|
22
26
|
if (!storage)
|
|
23
27
|
return;
|
|
@@ -63,6 +67,7 @@ function createPersistingChannel(parent, storage, threadId, logger) {
|
|
|
63
67
|
});
|
|
64
68
|
});
|
|
65
69
|
};
|
|
70
|
+
const runToolCallIndex = new Map();
|
|
66
71
|
const channel = {
|
|
67
72
|
channelId: parent.channelId,
|
|
68
73
|
openingData: parent.openingData,
|
|
@@ -75,6 +80,9 @@ function createPersistingChannel(parent, storage, threadId, logger) {
|
|
|
75
80
|
get totalUsage() {
|
|
76
81
|
return totalUsage;
|
|
77
82
|
},
|
|
83
|
+
get runToolCalls() {
|
|
84
|
+
return runToolCalls;
|
|
85
|
+
},
|
|
78
86
|
flush: flushStep,
|
|
79
87
|
close: () => parent.close(),
|
|
80
88
|
sendBinary: (data) => parent.sendBinary(data),
|
|
@@ -84,6 +92,26 @@ function createPersistingChannel(parent, storage, threadId, logger) {
|
|
|
84
92
|
// report the fragment it got through even with persistence turned off.
|
|
85
93
|
if (event.type === 'text-delta')
|
|
86
94
|
fullText += event.text;
|
|
95
|
+
if (event.type === 'tool-call') {
|
|
96
|
+
runToolCallIndex.set(event.toolCallId, runToolCalls.length);
|
|
97
|
+
runToolCalls.push({
|
|
98
|
+
name: event.toolName,
|
|
99
|
+
args: event.args,
|
|
100
|
+
result: '',
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
if (event.type === 'tool-result') {
|
|
104
|
+
const index = runToolCallIndex.get(event.toolCallId);
|
|
105
|
+
const result = typeof event.result === 'string'
|
|
106
|
+
? event.result
|
|
107
|
+
: JSON.stringify(event.result);
|
|
108
|
+
const call = index === undefined ? undefined : runToolCalls[index];
|
|
109
|
+
if (call) {
|
|
110
|
+
call.result = result;
|
|
111
|
+
if (event.error)
|
|
112
|
+
call.error = event.error;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
87
115
|
if (storage) {
|
|
88
116
|
switch (event.type) {
|
|
89
117
|
case 'text-delta':
|
|
@@ -103,6 +131,7 @@ function createPersistingChannel(parent, storage, threadId, logger) {
|
|
|
103
131
|
result: typeof event.result === 'string'
|
|
104
132
|
? event.result
|
|
105
133
|
: JSON.stringify(event.result),
|
|
134
|
+
...(event.error ? { error: event.error } : {}),
|
|
106
135
|
});
|
|
107
136
|
break;
|
|
108
137
|
case 'generative-ui':
|
|
@@ -129,36 +158,49 @@ function createPersistingChannel(parent, storage, threadId, logger) {
|
|
|
129
158
|
};
|
|
130
159
|
return channel;
|
|
131
160
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
161
|
+
/**
|
|
162
|
+
* Agents already warned about, so a per-request hook does not become a
|
|
163
|
+
* per-request log line.
|
|
164
|
+
*/
|
|
165
|
+
const warnedUnstreamedOutputHooks = new Set();
|
|
166
|
+
/**
|
|
167
|
+
* `modifyOutput` does not run on a streamed run at all. Nothing here could act
|
|
168
|
+
* on what it returns — the text has already reached the client, and
|
|
169
|
+
* `createPersistingChannel` flushes each step to storage as it goes, so by the
|
|
170
|
+
* time the run ends the transcript is already written.
|
|
171
|
+
*
|
|
172
|
+
* Rewriting on this path belongs to `modifyOutputStream`, which genuinely
|
|
173
|
+
* works: the stream middleware wraps the persisting channel, so what is stored
|
|
174
|
+
* and accumulated is already what the client was sent. A middleware that
|
|
175
|
+
* rewrites in `modifyOutput` only — a redaction hook, typically — is therefore
|
|
176
|
+
* silently ineffective when the agent is streamed, and is told so once.
|
|
177
|
+
*/
|
|
178
|
+
const warnUnstreamedOutputHooks = (agentName, aiMiddlewares, logger) => {
|
|
179
|
+
if (warnedUnstreamedOutputHooks.has(agentName))
|
|
180
|
+
return;
|
|
181
|
+
const unstreamed = aiMiddlewares.some((mw) => mw.modifyOutput && !mw.modifyOutputStream);
|
|
182
|
+
if (!unstreamed)
|
|
183
|
+
return;
|
|
184
|
+
warnedUnstreamedOutputHooks.add(agentName);
|
|
185
|
+
logger?.warn(`Agent '${agentName}' has AI middleware with modifyOutput but no modifyOutputStream — modifyOutput does not apply to streamed runs. Implement modifyOutputStream to affect a streamed reply.`);
|
|
186
|
+
};
|
|
187
|
+
async function postStreamCleanup(persistingChannel, aiRunState, runId, run) {
|
|
188
|
+
await finalizeAgentRun(aiRunState, {
|
|
189
|
+
runId,
|
|
190
|
+
agentName: run.agentName,
|
|
191
|
+
threadId: run.threadId,
|
|
192
|
+
resourceId: run.resourceId,
|
|
193
|
+
input: run.input,
|
|
194
|
+
// Already what the client received: the stream middleware wraps the
|
|
195
|
+
// persisting channel, so both were accumulated post-rewrite.
|
|
196
|
+
text: persistingChannel.fullText,
|
|
197
|
+
steps: [
|
|
198
|
+
{
|
|
199
|
+
usage: persistingChannel.totalUsage,
|
|
200
|
+
toolCalls: persistingChannel.runToolCalls,
|
|
201
|
+
},
|
|
202
|
+
],
|
|
203
|
+
usage: persistingChannel.totalUsage,
|
|
162
204
|
});
|
|
163
205
|
}
|
|
164
206
|
async function runStreamStepLoop(params) {
|
|
@@ -448,6 +490,7 @@ export async function streamAIAgent(agentName, input, channel, params, agentSess
|
|
|
448
490
|
if (storage) {
|
|
449
491
|
await storage.saveMessages(threadId, [persistedUserMessage]);
|
|
450
492
|
}
|
|
493
|
+
warnUnstreamedOutputHooks(agentName, aiMiddlewares, singletonServices.logger);
|
|
451
494
|
const streamMiddleware = aiMiddlewares
|
|
452
495
|
.filter((mw) => mw.modifyOutputStream)
|
|
453
496
|
.map((mw) => {
|
|
@@ -538,7 +581,12 @@ export async function streamAIAgent(agentName, input, channel, params, agentSess
|
|
|
538
581
|
await handleCredentialRequests(loopResult.credentialRequests, runId, channel, aiRunState, persistingChannel);
|
|
539
582
|
return persistingChannel.fullText;
|
|
540
583
|
}
|
|
541
|
-
await postStreamCleanup(persistingChannel,
|
|
584
|
+
await postStreamCleanup(persistingChannel, aiRunState, runId, {
|
|
585
|
+
agentName,
|
|
586
|
+
threadId,
|
|
587
|
+
resourceId: input.resourceId,
|
|
588
|
+
input: lastUserMessageText(runnerParams.messages),
|
|
589
|
+
});
|
|
542
590
|
// knowledge: decisions/internals/the-agent-done-event-goes-through-the-middleware-and-is-awaited.md
|
|
543
591
|
await outputChannel.send({ type: 'done' });
|
|
544
592
|
channel.close();
|
|
@@ -766,18 +814,19 @@ export async function resumeAIAgent(input, channel, params, options) {
|
|
|
766
814
|
}
|
|
767
815
|
const toolArgs = typeof pending.args === 'string' ? JSON.parse(pending.args) : pending.args;
|
|
768
816
|
let toolResult;
|
|
769
|
-
let
|
|
817
|
+
let toolError;
|
|
770
818
|
try {
|
|
771
819
|
toolResult = await matchingTool.execute(toolArgs);
|
|
772
820
|
}
|
|
773
821
|
catch (execErr) {
|
|
774
822
|
if (execErr?.payload?.error === 'missing_credential') {
|
|
775
823
|
toolResult = execErr.payload;
|
|
824
|
+
toolError = 'missing_credential';
|
|
776
825
|
}
|
|
777
826
|
else {
|
|
778
|
-
|
|
827
|
+
toolError = execErr instanceof Error ? execErr.message : String(execErr);
|
|
828
|
+
toolResult = `Error: ${toolError}`;
|
|
779
829
|
}
|
|
780
|
-
isError = true;
|
|
781
830
|
}
|
|
782
831
|
const resultStr = typeof toolResult === 'string' ? toolResult : JSON.stringify(toolResult);
|
|
783
832
|
if (storage) {
|
|
@@ -801,7 +850,7 @@ export async function resumeAIAgent(input, channel, params, options) {
|
|
|
801
850
|
toolCallId: input.toolCallId,
|
|
802
851
|
toolName: pending.toolName,
|
|
803
852
|
result: toolResult,
|
|
804
|
-
...(
|
|
853
|
+
...(toolError ? { error: toolError } : {}),
|
|
805
854
|
});
|
|
806
855
|
}
|
|
807
856
|
const updatedRun = await aiRunState.getRun(run.runId);
|
|
@@ -845,6 +894,7 @@ async function continueAfterToolResult(run, agent, packageName, resolvedName, st
|
|
|
845
894
|
const { messages: modifiedMessages, instructions: modifiedInstructions } = await applyInputMiddleware(aiMiddlewares, singletonServices, { messages: trimmedMessages, instructions: instructions }, sharedNotes);
|
|
846
895
|
// knowledge: decisions/internals/a-resumed-agent-turn-is-as-interruptible-as-the-first.md
|
|
847
896
|
const interruptHandle = registerInterruptibleRun(run.runId);
|
|
897
|
+
warnUnstreamedOutputHooks(run.agentName, aiMiddlewares, singletonServices.logger);
|
|
848
898
|
const streamMiddleware = aiMiddlewares
|
|
849
899
|
.filter((mw) => mw.modifyOutputStream)
|
|
850
900
|
.map((mw) => {
|
|
@@ -922,7 +972,10 @@ async function continueAfterToolResult(run, agent, packageName, resolvedName, st
|
|
|
922
972
|
await handleCredentialRequests(loopResult.credentialRequests, run.runId, channel, aiRunState, persistingChannel);
|
|
923
973
|
return;
|
|
924
974
|
}
|
|
925
|
-
await postStreamCleanup(persistingChannel,
|
|
975
|
+
await postStreamCleanup(persistingChannel, aiRunState, run.runId, {
|
|
976
|
+
...run,
|
|
977
|
+
input: lastUserMessageText(runnerParams.messages),
|
|
978
|
+
});
|
|
926
979
|
// knowledge: decisions/internals/the-agent-done-event-goes-through-the-middleware-and-is-awaited.md
|
|
927
980
|
await wrappedChannel.send({ type: 'done' });
|
|
928
981
|
channel.close();
|
|
@@ -43,6 +43,13 @@ export interface AIToolResult {
|
|
|
43
43
|
id: string;
|
|
44
44
|
name: string;
|
|
45
45
|
result: string;
|
|
46
|
+
/**
|
|
47
|
+
* Set when the tool threw rather than returned. Carried separately from
|
|
48
|
+
* `result`, which is a rendered string by the time it is persisted — a tool
|
|
49
|
+
* may legitimately return text beginning `Error:`, so the prefix cannot be
|
|
50
|
+
* read as a failure signal.
|
|
51
|
+
*/
|
|
52
|
+
error?: string;
|
|
46
53
|
}
|
|
47
54
|
export interface AIMessage {
|
|
48
55
|
id: string;
|
|
@@ -79,6 +86,8 @@ export interface AIAgentStep {
|
|
|
79
86
|
name: string;
|
|
80
87
|
args: Record<string, unknown>;
|
|
81
88
|
result: string;
|
|
89
|
+
/** The failure message, when the tool threw rather than returned. */
|
|
90
|
+
error?: string;
|
|
82
91
|
}[];
|
|
83
92
|
}
|
|
84
93
|
export interface AIAgentInputAttachment {
|
|
@@ -216,6 +225,21 @@ export interface PikkuAIMiddlewareHooks<State extends Record<string, unknown> =
|
|
|
216
225
|
*/
|
|
217
226
|
signal?: AbortSignal;
|
|
218
227
|
}) => Promise<AIStreamEvent | AIStreamEvent[] | null> | AIStreamEvent | AIStreamEvent[] | null;
|
|
228
|
+
/**
|
|
229
|
+
* The last chance to rewrite what the run produced, before it is persisted
|
|
230
|
+
* and returned.
|
|
231
|
+
*
|
|
232
|
+
* It does **not** run on a streamed run: there the text has already reached
|
|
233
|
+
* the client and each step is flushed to storage as it goes, so nothing could
|
|
234
|
+
* act on what this returned. Use {@link modifyOutputStream} to rewrite a
|
|
235
|
+
* streamed reply — a middleware that implements only this one is warned about
|
|
236
|
+
* when an agent it is attached to streams.
|
|
237
|
+
*
|
|
238
|
+
* `toolCalls` is here so a redaction pass covers the whole run record rather
|
|
239
|
+
* than just the visible answer: the tool arguments and results are persisted
|
|
240
|
+
* and handed to anything that grades the run, and scrubbing the reply alone
|
|
241
|
+
* leaves them untouched.
|
|
242
|
+
*/
|
|
219
243
|
modifyOutput?: (services: Services, ctx: {
|
|
220
244
|
text: string;
|
|
221
245
|
messages: AIMessage[];
|
|
@@ -223,12 +247,15 @@ export interface PikkuAIMiddlewareHooks<State extends Record<string, unknown> =
|
|
|
223
247
|
inputTokens: number;
|
|
224
248
|
outputTokens: number;
|
|
225
249
|
};
|
|
250
|
+
toolCalls: NonNullable<AIAgentStep['toolCalls']>;
|
|
226
251
|
}) => Promise<{
|
|
227
252
|
text: string;
|
|
228
253
|
messages: AIMessage[];
|
|
254
|
+
toolCalls?: NonNullable<AIAgentStep['toolCalls']>;
|
|
229
255
|
}> | {
|
|
230
256
|
text: string;
|
|
231
257
|
messages: AIMessage[];
|
|
258
|
+
toolCalls?: NonNullable<AIAgentStep['toolCalls']>;
|
|
232
259
|
};
|
|
233
260
|
beforeToolCall?: (services: Services, ctx: {
|
|
234
261
|
toolName: string;
|
|
@@ -262,6 +289,8 @@ export interface PikkuAIMiddlewareHooks<State extends Record<string, unknown> =
|
|
|
262
289
|
toolCallId: string;
|
|
263
290
|
toolName: string;
|
|
264
291
|
result: unknown;
|
|
292
|
+
/** Set when the tool threw rather than returned. */
|
|
293
|
+
error?: string;
|
|
265
294
|
}[];
|
|
266
295
|
usage: {
|
|
267
296
|
inputTokens: number;
|
|
@@ -282,7 +311,7 @@ export type AIAgentMemoryConfig = {
|
|
|
282
311
|
lastMessages?: number;
|
|
283
312
|
workingMemory?: unknown;
|
|
284
313
|
};
|
|
285
|
-
export type CoreAIAgent<PikkuPermission = CorePikkuPermission<any, any>, PikkuMiddleware = CorePikkuMiddleware<any>, Scope extends string = string> = {
|
|
314
|
+
export type CoreAIAgent<PikkuPermission = CorePikkuPermission<any, any>, PikkuMiddleware = CorePikkuMiddleware<any>, Scope extends string = string, Scorer extends string = string> = {
|
|
286
315
|
name: string;
|
|
287
316
|
description: string;
|
|
288
317
|
summary?: string;
|
|
@@ -308,6 +337,16 @@ export type CoreAIAgent<PikkuPermission = CorePikkuPermission<any, any>, PikkuMi
|
|
|
308
337
|
tools?: unknown[];
|
|
309
338
|
agents?: unknown[];
|
|
310
339
|
workflows?: unknown[];
|
|
340
|
+
/**
|
|
341
|
+
* Grades this agent's finished runs on live traffic, named by the generated
|
|
342
|
+
* `ScorerName` union rather than by `ref()` — a scorer is not a function, so
|
|
343
|
+
* there is nothing in the function map for a ref to resolve against.
|
|
344
|
+
*
|
|
345
|
+
* A reference-based judge listed here is never sampled: live traffic has no
|
|
346
|
+
* answer key. Scenarios name scorers directly and may grade with scorers an
|
|
347
|
+
* agent does not ship with.
|
|
348
|
+
*/
|
|
349
|
+
scorers?: Scorer[];
|
|
311
350
|
agentMode?: 'delegate' | 'supervise';
|
|
312
351
|
memory?: AIAgentMemoryConfig;
|
|
313
352
|
maxSteps?: number;
|
|
@@ -382,6 +421,12 @@ export type AIStreamEvent = {
|
|
|
382
421
|
toolCallId: string;
|
|
383
422
|
toolName: string;
|
|
384
423
|
result: unknown;
|
|
424
|
+
/**
|
|
425
|
+
* The failure message, set when the tool threw rather than returned.
|
|
426
|
+
* Carried explicitly because a tool may legitimately return text that
|
|
427
|
+
* reads like an error, so `result` cannot be matched on to tell.
|
|
428
|
+
*/
|
|
429
|
+
error?: string;
|
|
385
430
|
agent?: string;
|
|
386
431
|
session?: string;
|
|
387
432
|
} | {
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
export { agent, agentStream, agentResume, agentApprove, agentInterrupt, } from './ai-agent-helpers.js';
|
|
2
|
-
export { wrapChannelWithAGUI
|
|
2
|
+
export { wrapChannelWithAGUI } from './ai-agent-agui.js';
|
|
3
3
|
export { runAIAgent, resumeAIAgentSync } from './ai-agent-runner.js';
|
|
4
|
+
export { resolveModelAlias } from './ai-agent-model-config.js';
|
|
4
5
|
export { streamAIAgent, resumeAIAgent, interruptAIAgent, } from './ai-agent-stream.js';
|
|
5
|
-
export { voiceInput,
|
|
6
|
+
export { voiceInput, NoSpeechDetectedError, SPOKEN_TURN, SPOKEN_TRANSCRIPT, } from './voice-input.js';
|
|
6
7
|
export { voiceOutput, unspeakableScripts, voiceForText, type SpeakableScripts, } from './voice-output.js';
|
|
7
|
-
export { AgentInterruptedError,
|
|
8
|
-
export type { AgentInterruption, AgentInterruptResult, InterruptibleRunHandle,
|
|
9
|
-
export { type RunAIAgentParams, type StreamAIAgentOptions, ToolApprovalRequired, ToolCredentialRequired, canAccessThread, isOwnedByPrincipal,
|
|
10
|
-
export { addAIAgent,
|
|
11
|
-
export type { AIAgentInput,
|
|
8
|
+
export { AgentInterruptedError, signalRunInterrupt, } from './ai-agent-interrupt.js';
|
|
9
|
+
export type { AgentInterruption, AgentInterruptResult, InterruptibleRunHandle, } from './ai-agent-interrupt.js';
|
|
10
|
+
export { type RunAIAgentParams, type StreamAIAgentOptions, ToolApprovalRequired, ToolCredentialRequired, canAccessThread, isOwnedByPrincipal, threadOwnerConstraint, } from './ai-agent-prepare.js';
|
|
11
|
+
export { addAIAgent, } from './ai-agent-registry.js';
|
|
12
|
+
export type { AIAgentInput, AIAgentMeta, AIAgentMemoryConfig, AIAgentStep, AIContentPart, AgentRunRow, AgentRunService, AgentRunState, AIMessage, AIStreamChannel, AIStreamEvent, AIThread, CoreAIAgent, PendingApproval, PikkuAIMiddlewareHooks, } from './ai-agent.types.js';
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
export { agent, agentStream, agentResume, agentApprove, agentInterrupt, } from './ai-agent-helpers.js';
|
|
2
2
|
export { wrapChannelWithAGUI } from './ai-agent-agui.js';
|
|
3
3
|
export { runAIAgent, resumeAIAgentSync } from './ai-agent-runner.js';
|
|
4
|
+
export { resolveModelAlias } from './ai-agent-model-config.js';
|
|
4
5
|
export { streamAIAgent, resumeAIAgent, interruptAIAgent, } from './ai-agent-stream.js';
|
|
5
|
-
export { voiceInput,
|
|
6
|
+
export { voiceInput, NoSpeechDetectedError, SPOKEN_TURN, SPOKEN_TRANSCRIPT, } from './voice-input.js';
|
|
6
7
|
export { voiceOutput, unspeakableScripts, voiceForText, } from './voice-output.js';
|
|
7
|
-
export { AgentInterruptedError,
|
|
8
|
-
export { ToolApprovalRequired, ToolCredentialRequired, canAccessThread, isOwnedByPrincipal,
|
|
9
|
-
export { addAIAgent,
|
|
8
|
+
export { AgentInterruptedError, signalRunInterrupt, } from './ai-agent-interrupt.js';
|
|
9
|
+
export { ToolApprovalRequired, ToolCredentialRequired, canAccessThread, isOwnedByPrincipal, threadOwnerConstraint, } from './ai-agent-prepare.js';
|
|
10
|
+
export { addAIAgent, } from './ai-agent-registry.js';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ScoreJob, ScorerOutput } from './ai-scorer.types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Grade one run with one scorer.
|
|
4
|
+
*
|
|
5
|
+
* The single path both callers take — the lane worker on live traffic and the
|
|
6
|
+
* scenario grading RPC — so a scenario's grade is the same computation the
|
|
7
|
+
* production sampler would have made, not an approximation of it.
|
|
8
|
+
*
|
|
9
|
+
* Persisting is optional because the two callers differ on it: a live grade is
|
|
10
|
+
* only useful once recorded, while a scenario asserts on the returned value and
|
|
11
|
+
* runs against servers that may have no run-state adapter at all.
|
|
12
|
+
*/
|
|
13
|
+
export declare const gradeRun: (job: ScoreJob, services: {
|
|
14
|
+
aiAgentRunner?: unknown;
|
|
15
|
+
aiRunState?: {
|
|
16
|
+
saveScore: (score: {
|
|
17
|
+
runId: string;
|
|
18
|
+
scorerName: string;
|
|
19
|
+
score: number;
|
|
20
|
+
reason?: string;
|
|
21
|
+
metadata?: Record<string, unknown>;
|
|
22
|
+
}) => Promise<void>;
|
|
23
|
+
};
|
|
24
|
+
}, options: {
|
|
25
|
+
persist: boolean;
|
|
26
|
+
}) => Promise<ScorerOutput>;
|