@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
package/dist/services/index.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
export { LogLevel } from './logger.js';
|
|
2
2
|
export { ScopedSecretService } from './scoped-secret-service.js';
|
|
3
|
-
export {
|
|
3
|
+
export { ScopedCredentialService } from './scoped-credential-service.js';
|
|
4
|
+
export { PikkuSessionService, createMiddlewareSessionWireProps, } from './user-session-service.js';
|
|
4
5
|
export { TypedSecretService } from './typed-secret-service.js';
|
|
5
|
-
export { PikkuCredentialWireService
|
|
6
|
+
export { PikkuCredentialWireService } from './credential-wire-service.js';
|
|
6
7
|
export { TypedVariablesService } from './typed-variables-service.js';
|
|
7
8
|
export { LocalSecretService } from './local-secrets.js';
|
|
8
9
|
export { LocalEmailService } from './local-email-service.js';
|
|
@@ -16,11 +17,10 @@ export { InMemoryTriggerService } from './in-memory-trigger-service.js';
|
|
|
16
17
|
export { InMemoryAIRunStateService } from './in-memory-ai-run-state-service.js';
|
|
17
18
|
export { LocalGatewayService } from './local-gateway-service.js';
|
|
18
19
|
export type { ContentService, SignContentKeyArgs, SignURLArgs, GetUploadURLArgs, UploadURLResult, BucketKeyArgs, WriteFileArgs, CopyFileArgs, } from './content-service.js';
|
|
19
|
-
export type { ScenarioPersona, ResolvedPersona,
|
|
20
|
-
export type { HttpPersonasConfig } from './http-personas.js';
|
|
20
|
+
export type { ScenarioPersona, ResolvedPersona, ScenarioPersonas, } from './personas-service.js';
|
|
21
21
|
export type { JWTService } from './jwt-service.js';
|
|
22
|
-
export type { EmailService,
|
|
23
|
-
export { DEFAULT_WEBHOOK_RETRIES,
|
|
22
|
+
export type { EmailService, SendEmailInput, SendEmailResult, SendHTMLEmailInput, SendTemplateEmailInput, SendTextEmailInput, } from './email-service.js';
|
|
23
|
+
export { DEFAULT_WEBHOOK_RETRIES, PIKKU_OUTGOING_WEBHOOK_QUEUE_NAME, WebhookService, type SendWebhookInput, type SendWebhookResult, type WebhookAttemptResult, type WebhookDeliveryRecord, type WebhookDeliveryWithAttempts, type WebhookJobData, type WebhookServiceConfig, } from './webhook-service.js';
|
|
24
24
|
export type { Logger } from './logger.js';
|
|
25
25
|
export type { SecretService, SecretValues } from './secret-service.js';
|
|
26
26
|
export type { VariablesService } from './variables-service.js';
|
|
@@ -31,23 +31,22 @@ export type { TriggerService } from './trigger-service.js';
|
|
|
31
31
|
export type { GatewayService } from './gateway-service.js';
|
|
32
32
|
export type { DeploymentService, DeploymentConfig, DeploymentInfo, DeploymentServiceConfig, } from './deployment-service.js';
|
|
33
33
|
export type { AIStorageService } from './ai-storage-service.js';
|
|
34
|
-
export type { AIAgentRunnerParams, AIAgentRunnerResult, AIAgentStepResult,
|
|
34
|
+
export type { AIAgentRunnerParams, AIAgentRunnerResult, AIAgentStepResult, AIAgentRunnerService, } from './ai-agent-runner-service.js';
|
|
35
35
|
export type { AIEmbeddingService } from './ai-embedding-service.js';
|
|
36
|
-
export type { CreateRunInput, AIRunStateService, } from './ai-run-state-service.js';
|
|
37
|
-
export type {
|
|
36
|
+
export type { CreateRunInput, SaveScoreInput, AIRunStateService, } from './ai-run-state-service.js';
|
|
37
|
+
export type { CredentialMeta } from './typed-secret-service.js';
|
|
38
38
|
export type { CredentialService } from './credential-service.js';
|
|
39
39
|
export { TypedCredentialService } from './typed-credential-service.js';
|
|
40
|
-
export type {
|
|
41
|
-
export type {
|
|
40
|
+
export type { CredentialMetaInfo } from './typed-credential-service.js';
|
|
41
|
+
export type { VariableMeta } from './typed-variables-service.js';
|
|
42
42
|
export type { MetaService } from './meta-service.js';
|
|
43
43
|
export type { SessionStore } from './session-store.js';
|
|
44
44
|
export type { ScopeService, Role } from './scope-service.js';
|
|
45
|
-
export { assertRoleIsMutable, assertRoleNameAvailable, roleLockReason, } from './system-role-guard.js';
|
|
46
45
|
export type { IsSystemRole } from './system-role-guard.js';
|
|
47
|
-
export { NoopAuditService, createInvocationAudit
|
|
48
|
-
export type { AuditConfig, AuditDurability, AuditEvent, AuditEventBatch, AuditLog,
|
|
46
|
+
export { NoopAuditService, createInvocationAudit } from './audit-service.js';
|
|
47
|
+
export type { AuditConfig, AuditDurability, AuditEvent, AuditEventBatch, AuditLog, AuditService, AuditUserIdentity, ResolvedAuditConfig, } from './audit-service.js';
|
|
49
48
|
export { InMemorySessionStore } from './in-memory-session-store.js';
|
|
50
|
-
export type { MCPMeta, RPCMetaRecord, ServiceMeta, ServicesMetaRecord, MiddlewareDefinitionMeta, MiddlewareInstanceMeta, GroupMeta, MiddlewareGroupsMeta, PermissionDefinitionMeta, PermissionsGroupsMeta, FunctionsMeta, FunctionMeta, MiddlewareMeta, PermissionMeta, AgentsMeta, AgentMeta, EmailsMeta, EmailTemplateMeta,
|
|
51
|
-
export type { CoverageService,
|
|
49
|
+
export type { MCPMeta, RPCMetaRecord, ServiceMeta, ServicesMetaRecord, MiddlewareDefinitionMeta, MiddlewareInstanceMeta, GroupMeta, MiddlewareGroupsMeta, PermissionDefinitionMeta, PermissionsGroupsMeta, FunctionsMeta, FunctionMeta, MiddlewareMeta, PermissionMeta, AgentsMeta, AgentMeta, EmailsMeta, EmailTemplateMeta, } from './meta-service.js';
|
|
50
|
+
export type { CoverageService, ScriptCoverage, FunctionCoverageEntry, FunctionCoverageReport, CoverageFunctionMeta, } from './v8-coverage-service.js';
|
|
52
51
|
export { StubTracker, createStubProxy, getStubTracker, isTestRun, stub, spy, type StubCall, } from './stub-tracker.js';
|
|
53
52
|
export { SecretHostNotAllowedError, assertSecretAllowedForHost, } from './secret-host-binding.js';
|
package/dist/services/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
export { LogLevel } from './logger.js';
|
|
2
2
|
export { ScopedSecretService } from './scoped-secret-service.js';
|
|
3
|
-
export {
|
|
3
|
+
export { ScopedCredentialService } from './scoped-credential-service.js';
|
|
4
|
+
export { PikkuSessionService, createMiddlewareSessionWireProps, } from './user-session-service.js';
|
|
4
5
|
export { TypedSecretService } from './typed-secret-service.js';
|
|
5
|
-
export { PikkuCredentialWireService
|
|
6
|
+
export { PikkuCredentialWireService } from './credential-wire-service.js';
|
|
6
7
|
export { TypedVariablesService } from './typed-variables-service.js';
|
|
7
8
|
export { LocalSecretService } from './local-secrets.js';
|
|
8
9
|
export { LocalEmailService } from './local-email-service.js';
|
|
@@ -15,10 +16,9 @@ export { InMemoryQueueService } from './in-memory-queue-service.js';
|
|
|
15
16
|
export { InMemoryTriggerService } from './in-memory-trigger-service.js';
|
|
16
17
|
export { InMemoryAIRunStateService } from './in-memory-ai-run-state-service.js';
|
|
17
18
|
export { LocalGatewayService } from './local-gateway-service.js';
|
|
18
|
-
export { DEFAULT_WEBHOOK_RETRIES,
|
|
19
|
+
export { DEFAULT_WEBHOOK_RETRIES, PIKKU_OUTGOING_WEBHOOK_QUEUE_NAME, WebhookService, } from './webhook-service.js';
|
|
19
20
|
export { TypedCredentialService } from './typed-credential-service.js';
|
|
20
|
-
export {
|
|
21
|
-
export { NoopAuditService, createInvocationAudit, resolveAuditConfig, resolveAuditUserIdentityFromWire, } from './audit-service.js';
|
|
21
|
+
export { NoopAuditService, createInvocationAudit } from './audit-service.js';
|
|
22
22
|
export { InMemorySessionStore } from './in-memory-session-store.js';
|
|
23
23
|
export { StubTracker, createStubProxy, getStubTracker, isTestRun, stub, spy, } from './stub-tracker.js';
|
|
24
24
|
export { SecretHostNotAllowedError, assertSecretAllowedForHost, } from './secret-host-binding.js';
|
|
@@ -5,7 +5,8 @@ import type { ScheduledTasksMeta } from '../wirings/scheduler/scheduler.types.js
|
|
|
5
5
|
import type { QueueWorkersMeta } from '../wirings/queue/queue.types.js';
|
|
6
6
|
import type { CLIMeta } from '../wirings/cli/cli.types.js';
|
|
7
7
|
import type { MCPResourceMeta, MCPToolMeta, MCPPromptMeta } from '../wirings/mcp/mcp.types.js';
|
|
8
|
-
import type {
|
|
8
|
+
import type { WorkflowsMeta } from '../wirings/workflow/workflow.types.js';
|
|
9
|
+
import type { FeaturesMeta } from '../wirings/workflow/scenario.types.js';
|
|
9
10
|
import type { ResolvedPersona } from './personas-service.js';
|
|
10
11
|
import type { SystemRoleDefinitionsMeta } from '../wirings/role/role.types.js';
|
|
11
12
|
import type { TriggerMeta, TriggerSourceMeta } from '../wirings/trigger/trigger.types.js';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { CredentialService } from './credential-service.js';
|
|
2
|
+
/**
|
|
3
|
+
* A `CredentialService` narrowed to the credentials a package declared.
|
|
4
|
+
*
|
|
5
|
+
* Unlike `ScopedSecretService` this stays writable — an addon refreshing its
|
|
6
|
+
* own OAuth token is the normal case. What it cannot do is reach a credential
|
|
7
|
+
* it never declared, or enumerate the app's users.
|
|
8
|
+
*/
|
|
9
|
+
export declare class ScopedCredentialService implements CredentialService {
|
|
10
|
+
private credentials;
|
|
11
|
+
private allowedNames;
|
|
12
|
+
constructor(credentials: CredentialService, allowedNames: Set<string>);
|
|
13
|
+
private assertAllowed;
|
|
14
|
+
get<T = unknown>(name: string, userId?: string): Promise<T | null>;
|
|
15
|
+
set(name: string, value: unknown, userId?: string): Promise<void>;
|
|
16
|
+
delete(name: string, userId?: string): Promise<void>;
|
|
17
|
+
has(name: string, userId?: string): Promise<boolean>;
|
|
18
|
+
getAll(userId: string): Promise<Record<string, unknown>>;
|
|
19
|
+
getUsersWithCredential(name: string): Promise<string[]>;
|
|
20
|
+
getAllUsers(): Promise<string[]>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A `CredentialService` narrowed to the credentials a package declared.
|
|
3
|
+
*
|
|
4
|
+
* Unlike `ScopedSecretService` this stays writable — an addon refreshing its
|
|
5
|
+
* own OAuth token is the normal case. What it cannot do is reach a credential
|
|
6
|
+
* it never declared, or enumerate the app's users.
|
|
7
|
+
*/
|
|
8
|
+
export class ScopedCredentialService {
|
|
9
|
+
credentials;
|
|
10
|
+
allowedNames;
|
|
11
|
+
constructor(credentials, allowedNames) {
|
|
12
|
+
this.credentials = credentials;
|
|
13
|
+
this.allowedNames = allowedNames;
|
|
14
|
+
}
|
|
15
|
+
assertAllowed(name) {
|
|
16
|
+
if (!this.allowedNames.has(name)) {
|
|
17
|
+
throw new Error(`Access denied to credential: ${name}`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
async get(name, userId) {
|
|
21
|
+
this.assertAllowed(name);
|
|
22
|
+
return this.credentials.get(name, userId);
|
|
23
|
+
}
|
|
24
|
+
async set(name, value, userId) {
|
|
25
|
+
this.assertAllowed(name);
|
|
26
|
+
return this.credentials.set(name, value, userId);
|
|
27
|
+
}
|
|
28
|
+
async delete(name, userId) {
|
|
29
|
+
this.assertAllowed(name);
|
|
30
|
+
return this.credentials.delete(name, userId);
|
|
31
|
+
}
|
|
32
|
+
async has(name, userId) {
|
|
33
|
+
this.assertAllowed(name);
|
|
34
|
+
return this.credentials.has(name, userId);
|
|
35
|
+
}
|
|
36
|
+
async getAll(userId) {
|
|
37
|
+
const all = await this.credentials.getAll(userId);
|
|
38
|
+
const scoped = {};
|
|
39
|
+
for (const name of this.allowedNames) {
|
|
40
|
+
if (name in all) {
|
|
41
|
+
scoped[name] = all[name];
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return scoped;
|
|
45
|
+
}
|
|
46
|
+
async getUsersWithCredential(name) {
|
|
47
|
+
this.assertAllowed(name);
|
|
48
|
+
return this.credentials.getUsersWithCredential(name);
|
|
49
|
+
}
|
|
50
|
+
async getAllUsers() {
|
|
51
|
+
throw new Error('Access denied: enumerating users is not allowed in a scoped credential service');
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -168,6 +168,82 @@ export const defineAiStorageServiceTests = (name, aiStorageService) => {
|
|
|
168
168
|
assert.ok(runs.length >= 1);
|
|
169
169
|
assert.ok(runs.every((r) => r.threadId === thread.id));
|
|
170
170
|
});
|
|
171
|
+
test('saveScore and getScores', async () => {
|
|
172
|
+
const thread = await storage.createThread('resource-score');
|
|
173
|
+
const now = new Date();
|
|
174
|
+
const runId = await storage.createRun({
|
|
175
|
+
agentName: 'scored-agent',
|
|
176
|
+
threadId: thread.id,
|
|
177
|
+
resourceId: 'resource-score',
|
|
178
|
+
status: 'completed',
|
|
179
|
+
usage: { inputTokens: 10, outputTokens: 5, model: 'test' },
|
|
180
|
+
createdAt: now,
|
|
181
|
+
updatedAt: now,
|
|
182
|
+
});
|
|
183
|
+
await storage.saveScore({
|
|
184
|
+
runId,
|
|
185
|
+
scorerName: 'tool-error-rate',
|
|
186
|
+
score: 1,
|
|
187
|
+
});
|
|
188
|
+
await storage.saveScore({
|
|
189
|
+
runId,
|
|
190
|
+
scorerName: 'helpfulness',
|
|
191
|
+
score: 0.75,
|
|
192
|
+
reason: 'answered the question but skipped the fee',
|
|
193
|
+
metadata: { subScores: { accuracy: 0.9 }, judgeTokens: 412 },
|
|
194
|
+
});
|
|
195
|
+
const scores = await storage.getScores(runId);
|
|
196
|
+
assert.equal(scores.length, 2);
|
|
197
|
+
const byName = new Map(scores.map((s) => [s.scorerName, s]));
|
|
198
|
+
const clean = byName.get('tool-error-rate');
|
|
199
|
+
assert.ok(clean);
|
|
200
|
+
assert.equal(clean.score, 1);
|
|
201
|
+
assert.equal(clean.reason, undefined);
|
|
202
|
+
assert.equal(clean.metadata, undefined);
|
|
203
|
+
const helpful = byName.get('helpfulness');
|
|
204
|
+
assert.ok(helpful);
|
|
205
|
+
// A fractional score has to survive the round trip: an integer column
|
|
206
|
+
// would quietly turn every grade into 0 or 1.
|
|
207
|
+
assert.equal(helpful.score, 0.75);
|
|
208
|
+
assert.equal(helpful.reason, 'answered the question but skipped the fee');
|
|
209
|
+
assert.deepEqual(helpful.metadata, {
|
|
210
|
+
subScores: { accuracy: 0.9 },
|
|
211
|
+
judgeTokens: 412,
|
|
212
|
+
});
|
|
213
|
+
assert.ok(helpful.createdAt instanceof Date);
|
|
214
|
+
});
|
|
215
|
+
test('a re-grade appends rather than replacing the grade that was acted on', async () => {
|
|
216
|
+
const thread = await storage.createThread('resource-regrade');
|
|
217
|
+
const now = new Date();
|
|
218
|
+
const runId = await storage.createRun({
|
|
219
|
+
agentName: 'regraded-agent',
|
|
220
|
+
threadId: thread.id,
|
|
221
|
+
resourceId: 'resource-regrade',
|
|
222
|
+
status: 'completed',
|
|
223
|
+
usage: { inputTokens: 1, outputTokens: 1, model: 'test' },
|
|
224
|
+
createdAt: now,
|
|
225
|
+
updatedAt: now,
|
|
226
|
+
});
|
|
227
|
+
await storage.saveScore({ runId, scorerName: 'helpfulness', score: 0.2 });
|
|
228
|
+
await storage.saveScore({ runId, scorerName: 'helpfulness', score: 0.8 });
|
|
229
|
+
const scores = await storage.getScores(runId);
|
|
230
|
+
assert.equal(scores.length, 2);
|
|
231
|
+
assert.deepEqual(scores.map((s) => s.score), [0.2, 0.8]);
|
|
232
|
+
});
|
|
233
|
+
test('getScores is empty for a run nothing graded', async () => {
|
|
234
|
+
const thread = await storage.createThread('resource-ungraded');
|
|
235
|
+
const now = new Date();
|
|
236
|
+
const runId = await storage.createRun({
|
|
237
|
+
agentName: 'ungraded-agent',
|
|
238
|
+
threadId: thread.id,
|
|
239
|
+
resourceId: 'resource-ungraded',
|
|
240
|
+
status: 'completed',
|
|
241
|
+
usage: { inputTokens: 1, outputTokens: 1, model: 'test' },
|
|
242
|
+
createdAt: now,
|
|
243
|
+
updatedAt: now,
|
|
244
|
+
});
|
|
245
|
+
assert.deepEqual(await storage.getScores(runId), []);
|
|
246
|
+
});
|
|
171
247
|
test('resolveApproval', async () => {
|
|
172
248
|
const thread = await storage.createThread('resource-8');
|
|
173
249
|
const now = new Date();
|
|
@@ -11,7 +11,8 @@ import type { PikkuMCP } from '../wirings/mcp/mcp.types.js';
|
|
|
11
11
|
import type { PikkuScheduledTask } from '../wirings/scheduler/scheduler.types.js';
|
|
12
12
|
import type { PikkuQueue, QueueService } from '../wirings/queue/queue.types.js';
|
|
13
13
|
import type { PikkuCLI } from '../wirings/cli/cli.types.js';
|
|
14
|
-
import type { PikkuWorkflowWire,
|
|
14
|
+
import type { PikkuWorkflowWire, WorkflowService, WorkflowServiceConfig, WorkflowStepWire } from '../wirings/workflow/workflow.types.js';
|
|
15
|
+
import type { PikkuScenarioWire } from '../wirings/workflow/scenario.types.js';
|
|
15
16
|
import type { PikkuBrowserWire, PikkuScenarioStepWire, ScenarioStepKind, ScenarioSurface } from '../wirings/workflow/scenario-step.types.js';
|
|
16
17
|
import type { PikkuGraphWire } from '../wirings/workflow/graph/workflow-graph.types.js';
|
|
17
18
|
import type { PikkuTrigger } from '../wirings/trigger/trigger.types.js';
|
|
@@ -142,8 +143,6 @@ export type FunctionRuntimeMeta = {
|
|
|
142
143
|
audit?: {
|
|
143
144
|
durability: AuditDurability;
|
|
144
145
|
};
|
|
145
|
-
/** Keeps the full `SecretService`. Set by the inspector, read by the runner. */
|
|
146
|
-
secretBroker?: boolean;
|
|
147
146
|
version?: number;
|
|
148
147
|
approvalRequired?: boolean;
|
|
149
148
|
approvalDescription?: string;
|
|
@@ -6,10 +6,12 @@ import type { CLIMeta, CLIProgramState } from '../wirings/cli/cli.types.js';
|
|
|
6
6
|
import type { HTTPMethod, CoreHTTPFunctionWiring, HTTPWiringsMeta } from '../wirings/http/http.types.js';
|
|
7
7
|
import type { CoreMCPResource, MCPResourceMeta, MCPToolMeta, CoreMCPPrompt, MCPPromptMeta } from '../wirings/mcp/mcp.types.js';
|
|
8
8
|
import type { CoreAIAgent, AIAgentMeta } from '../wirings/ai-agent/ai-agent.types.js';
|
|
9
|
+
import type { PikkuAIScorer, ScorerMeta } from '../wirings/ai-scorer/ai-scorer.types.js';
|
|
9
10
|
import type { CoreGateway, GatewaysMeta } from '../wirings/gateway/gateway.types.js';
|
|
10
11
|
import type { CoreQueueWorker, QueueWorkersMeta } from '../wirings/queue/queue.types.js';
|
|
11
12
|
import type { CoreScheduledTask, ScheduledTasksMeta } from '../wirings/scheduler/scheduler.types.js';
|
|
12
|
-
import type { CoreWorkflow,
|
|
13
|
+
import type { CoreWorkflow, WorkflowsRuntimeMeta } from '../wirings/workflow/workflow.types.js';
|
|
14
|
+
import type { CoreFeature } from '../wirings/workflow/scenario.types.js';
|
|
13
15
|
import type { CoreTrigger, CoreTriggerSource, TriggerMeta, TriggerSourceMeta } from '../wirings/trigger/trigger.types.js';
|
|
14
16
|
import type { FunctionsMeta, CorePikkuMiddleware, CorePikkuMiddlewareGroup, CreateConfig, CreateSingletonServices, CreateWireServices, CoreConfig, CoreSingletonServices, CoreServices, CoreUserSession } from './core.types.js';
|
|
15
17
|
import type { CorePikkuChannelMiddleware } from '../wirings/channel/channel.types.js';
|
|
@@ -40,6 +42,14 @@ export interface PikkuPackageState {
|
|
|
40
42
|
variableOverrides?: Record<string, string>;
|
|
41
43
|
/** Per-instance name-aliases: logical name the addon reads -> actual project credential name */
|
|
42
44
|
credentialOverrides?: Record<string, string>;
|
|
45
|
+
/** Secrets the host lends this instance, named as the addon reads them */
|
|
46
|
+
secretGrants?: string[];
|
|
47
|
+
/** Credentials the host lends this instance, named as the addon reads them */
|
|
48
|
+
credentialGrants?: string[];
|
|
49
|
+
/** Why this instance gets the whole `SecretService` rather than one scoped to its declared secrets */
|
|
50
|
+
globalSecrets?: string;
|
|
51
|
+
/** Why this instance gets the whole `CredentialService` rather than one scoped to its declared credentials */
|
|
52
|
+
globalCredentials?: string;
|
|
43
53
|
/** Set by `wireRemoteAddon`: this namespace is consumed remotely over HTTP, not bundled */
|
|
44
54
|
remote?: boolean;
|
|
45
55
|
/** Remote host base URL (wireRemoteAddon) — string or resolver over singleton services */
|
|
@@ -97,6 +107,10 @@ export interface PikkuPackageState {
|
|
|
97
107
|
agent: {
|
|
98
108
|
agents: Map<string, CoreAIAgent>;
|
|
99
109
|
agentsMeta: AIAgentMeta;
|
|
110
|
+
scorers: Map<string, PikkuAIScorer>;
|
|
111
|
+
scorersMeta: ScorerMeta;
|
|
112
|
+
/** Alias -> `provider/model`, from the `models` table in pikku.config.json. */
|
|
113
|
+
modelAliases: Record<string, string>;
|
|
100
114
|
};
|
|
101
115
|
gateway: {
|
|
102
116
|
gateways: Map<string, CoreGateway>;
|
|
@@ -141,5 +155,9 @@ export interface PikkuPackageState {
|
|
|
141
155
|
oauth2?: boolean;
|
|
142
156
|
}> | null;
|
|
143
157
|
requiredParentServices: string[] | null;
|
|
158
|
+
/** The secret keys this package is allowed to read, emitted by the CLI from
|
|
159
|
+
* what the package declares and is seen to read. `null` when the package
|
|
160
|
+
* was never analysed, which scopes it to nothing. */
|
|
161
|
+
declaredSecrets: string[] | null;
|
|
144
162
|
};
|
|
145
163
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export type {
|
|
1
|
+
export type { ActorFlowVerdict, ConverseOptions, TargetAgentDriver, } from './actor-flow.types.js';
|
|
2
2
|
export { runConversation, type RunConversationParams, type ActorLLM, } from './run-conversation.js';
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { AIAgentStep, AIMessage, PikkuAIMiddlewareHooks } from './ai-agent.types.js';
|
|
2
|
+
import type { AIRunStateService } from '../../services/ai-run-state-service.js';
|
|
3
|
+
export type RunUsage = {
|
|
4
|
+
inputTokens: number;
|
|
5
|
+
outputTokens: number;
|
|
6
|
+
model?: string;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Everything a finished run produced, after all middleware has had its say.
|
|
10
|
+
*
|
|
11
|
+
* One snapshot feeds persistence and anything that grades the run, so that what
|
|
12
|
+
* a scorer is shown is exactly what was stored — including the redactions.
|
|
13
|
+
*/
|
|
14
|
+
export type FinalizedRun = {
|
|
15
|
+
runId: string;
|
|
16
|
+
agentName: string;
|
|
17
|
+
threadId: string;
|
|
18
|
+
resourceId?: string;
|
|
19
|
+
/** The prompt the run answered — what a scorer grades the answer against. */
|
|
20
|
+
input: string;
|
|
21
|
+
text: string;
|
|
22
|
+
steps: AIAgentStep[];
|
|
23
|
+
usage: RunUsage;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* The prompt a run answered: the most recent user turn, which is what the model
|
|
27
|
+
* was last asked. On a resumed run the earlier turns are context, not the ask.
|
|
28
|
+
*/
|
|
29
|
+
export declare const lastUserMessageText: (messages: AIMessage[]) => string;
|
|
30
|
+
/**
|
|
31
|
+
* Run the `modifyOutput` chain over a finished non-streaming run.
|
|
32
|
+
*
|
|
33
|
+
* Reverse order, matching the input chain: the middleware registered first
|
|
34
|
+
* wraps the others, so it sees the output last.
|
|
35
|
+
*/
|
|
36
|
+
export declare const applyOutputMiddleware: (aiMiddlewares: PikkuAIMiddlewareHooks[], singletonServices: any, input: {
|
|
37
|
+
text: string;
|
|
38
|
+
messages: AIMessage[];
|
|
39
|
+
steps: AIAgentStep[];
|
|
40
|
+
usage: {
|
|
41
|
+
inputTokens: number;
|
|
42
|
+
outputTokens: number;
|
|
43
|
+
};
|
|
44
|
+
}) => Promise<{
|
|
45
|
+
text: string;
|
|
46
|
+
messages: AIMessage[];
|
|
47
|
+
steps: AIAgentStep[];
|
|
48
|
+
}>;
|
|
49
|
+
/**
|
|
50
|
+
* The one place a run ends successfully.
|
|
51
|
+
*
|
|
52
|
+
* Every path that completes a run — streamed, non-streamed, and resumed after a
|
|
53
|
+
* tool approval — goes through here, so that anything terminal is reachable
|
|
54
|
+
* from all of them and cannot be reordered by a middleware author. Nothing here
|
|
55
|
+
* may rewrite the run: by this point the output middleware has resolved and, on
|
|
56
|
+
* the streaming path, the client already has the reply.
|
|
57
|
+
*/
|
|
58
|
+
export declare const finalizeAgentRun: (aiRunState: AIRunStateService, run: FinalizedRun) => Promise<void>;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { pikkuState } from '../../pikku-state.js';
|
|
2
|
+
import { scoreFinishedRun } from '../ai-scorer/ai-scorer-live.js';
|
|
3
|
+
import { recordScoreSnapshot } from '../ai-scorer/ai-scorer-snapshots.js';
|
|
4
|
+
/**
|
|
5
|
+
* The prompt a run answered: the most recent user turn, which is what the model
|
|
6
|
+
* was last asked. On a resumed run the earlier turns are context, not the ask.
|
|
7
|
+
*/
|
|
8
|
+
export const lastUserMessageText = (messages) => {
|
|
9
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
10
|
+
const message = messages[i];
|
|
11
|
+
if (message?.role !== 'user')
|
|
12
|
+
continue;
|
|
13
|
+
if (typeof message.content === 'string')
|
|
14
|
+
return message.content;
|
|
15
|
+
if (Array.isArray(message.content)) {
|
|
16
|
+
return message.content
|
|
17
|
+
.filter((part) => part.type === 'text')
|
|
18
|
+
.map((part) => part.text)
|
|
19
|
+
.join('\n');
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return '';
|
|
23
|
+
};
|
|
24
|
+
const flattenToolCalls = (steps) => steps.flatMap((step) => step.toolCalls ?? []);
|
|
25
|
+
/**
|
|
26
|
+
* Push a rewritten flat tool-call list back onto the steps it came from,
|
|
27
|
+
* preserving the step boundaries. A hook that adds or drops calls would make
|
|
28
|
+
* the boundaries meaningless, so a length change collapses them into the last
|
|
29
|
+
* step rather than silently mis-attributing calls to the wrong step.
|
|
30
|
+
*/
|
|
31
|
+
const distributeToolCalls = (steps, toolCalls) => {
|
|
32
|
+
if (toolCalls.length !== flattenToolCalls(steps).length) {
|
|
33
|
+
return steps.map((step, index) => ({
|
|
34
|
+
...step,
|
|
35
|
+
toolCalls: index === steps.length - 1 ? toolCalls : [],
|
|
36
|
+
}));
|
|
37
|
+
}
|
|
38
|
+
let cursor = 0;
|
|
39
|
+
return steps.map((step) => {
|
|
40
|
+
if (!step.toolCalls)
|
|
41
|
+
return step;
|
|
42
|
+
const next = toolCalls.slice(cursor, cursor + step.toolCalls.length);
|
|
43
|
+
cursor += step.toolCalls.length;
|
|
44
|
+
return { ...step, toolCalls: next };
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Run the `modifyOutput` chain over a finished non-streaming run.
|
|
49
|
+
*
|
|
50
|
+
* Reverse order, matching the input chain: the middleware registered first
|
|
51
|
+
* wraps the others, so it sees the output last.
|
|
52
|
+
*/
|
|
53
|
+
export const applyOutputMiddleware = async (aiMiddlewares, singletonServices, input) => {
|
|
54
|
+
let text = input.text;
|
|
55
|
+
let messages = input.messages;
|
|
56
|
+
let steps = input.steps;
|
|
57
|
+
let toolCalls = flattenToolCalls(steps);
|
|
58
|
+
for (let i = aiMiddlewares.length - 1; i >= 0; i--) {
|
|
59
|
+
const mw = aiMiddlewares[i];
|
|
60
|
+
if (!mw.modifyOutput)
|
|
61
|
+
continue;
|
|
62
|
+
const result = await mw.modifyOutput(singletonServices, {
|
|
63
|
+
text,
|
|
64
|
+
messages,
|
|
65
|
+
usage: {
|
|
66
|
+
inputTokens: input.usage.inputTokens,
|
|
67
|
+
outputTokens: input.usage.outputTokens,
|
|
68
|
+
},
|
|
69
|
+
toolCalls,
|
|
70
|
+
});
|
|
71
|
+
text = result.text;
|
|
72
|
+
messages = result.messages;
|
|
73
|
+
if (result.toolCalls) {
|
|
74
|
+
toolCalls = result.toolCalls;
|
|
75
|
+
steps = distributeToolCalls(steps, toolCalls);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return { text, messages, steps };
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* The one place a run ends successfully.
|
|
82
|
+
*
|
|
83
|
+
* Every path that completes a run — streamed, non-streamed, and resumed after a
|
|
84
|
+
* tool approval — goes through here, so that anything terminal is reachable
|
|
85
|
+
* from all of them and cannot be reordered by a middleware author. Nothing here
|
|
86
|
+
* may rewrite the run: by this point the output middleware has resolved and, on
|
|
87
|
+
* the streaming path, the client already has the reply.
|
|
88
|
+
*/
|
|
89
|
+
export const finalizeAgentRun = async (aiRunState, run) => {
|
|
90
|
+
await aiRunState.updateRun(run.runId, {
|
|
91
|
+
status: 'completed',
|
|
92
|
+
...(run.usage.model
|
|
93
|
+
? {
|
|
94
|
+
usage: {
|
|
95
|
+
inputTokens: run.usage.inputTokens,
|
|
96
|
+
outputTokens: run.usage.outputTokens,
|
|
97
|
+
model: run.usage.model,
|
|
98
|
+
},
|
|
99
|
+
}
|
|
100
|
+
: {}),
|
|
101
|
+
});
|
|
102
|
+
// Read rather than `getSingletonServices()`: a process that never registered
|
|
103
|
+
// them grades nothing, which is not an error at the point a run has already
|
|
104
|
+
// succeeded.
|
|
105
|
+
const services = pikkuState(null, 'package', 'singletonServices');
|
|
106
|
+
if (!services)
|
|
107
|
+
return;
|
|
108
|
+
const snapshot = {
|
|
109
|
+
runId: run.runId,
|
|
110
|
+
agentName: run.agentName,
|
|
111
|
+
threadId: run.threadId,
|
|
112
|
+
...(run.resourceId !== undefined ? { resourceId: run.resourceId } : {}),
|
|
113
|
+
input: run.input,
|
|
114
|
+
output: run.text,
|
|
115
|
+
toolCalls: run.steps.flatMap((step) => (step.toolCalls ?? []).map((call) => ({
|
|
116
|
+
name: call.name,
|
|
117
|
+
args: call.args,
|
|
118
|
+
result: call.result,
|
|
119
|
+
...(call.error !== undefined ? { error: call.error } : {}),
|
|
120
|
+
}))),
|
|
121
|
+
usage: {
|
|
122
|
+
inputTokens: run.usage.inputTokens,
|
|
123
|
+
outputTokens: run.usage.outputTokens,
|
|
124
|
+
...(run.usage.model !== undefined ? { model: run.usage.model } : {}),
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
// The same object a scenario grades, so an asserted score and a sampled one
|
|
128
|
+
// are the same measurement. A no-op unless a dev server turned retention on.
|
|
129
|
+
recordScoreSnapshot(snapshot);
|
|
130
|
+
// Best-effort and last: the client already has its answer, so a grading
|
|
131
|
+
// failure must not surface as a failed run.
|
|
132
|
+
try {
|
|
133
|
+
await scoreFinishedRun(snapshot, services);
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
services.logger?.error(`[pikku] Live scoring failed for run ${run.runId}`, error);
|
|
137
|
+
}
|
|
138
|
+
};
|
|
@@ -240,6 +240,7 @@ export const persistOrphanedToolResults = async (handle, storage, threadId) => {
|
|
|
240
240
|
: typeof entry.result === 'string'
|
|
241
241
|
? entry.result
|
|
242
242
|
: JSON.stringify(entry.result),
|
|
243
|
+
...(entry.error ? { error: entry.error } : {}),
|
|
243
244
|
})),
|
|
244
245
|
undelivered: true,
|
|
245
246
|
createdAt: new Date(),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CoreSingletonServices } from '../../types/core.types.js';
|
|
2
|
-
import type { CoreAIAgent, AIAgentMemoryConfig, AIAgentInput, AIMessage } from './ai-agent.types.js';
|
|
2
|
+
import type { CoreAIAgent, AIAgentMemoryConfig, AIAgentInput, AIAgentStep, AIMessage } from './ai-agent.types.js';
|
|
3
3
|
import type { AIStorageService } from '../../services/ai-storage-service.js';
|
|
4
4
|
import type { Logger } from '../../services/logger.js';
|
|
5
5
|
import type { SchemaService } from '../../services/schema-service.js';
|
|
@@ -14,13 +14,7 @@ export declare function loadContextMessages(memoryConfig: AIAgentMemoryConfig |
|
|
|
14
14
|
export declare function saveMessages(storage: AIStorageService | undefined, threadId: string, resourceId: string, memoryConfig: AIAgentMemoryConfig | undefined, userMessage: AIMessage | null | undefined, result: {
|
|
15
15
|
text: string;
|
|
16
16
|
uiSpec?: unknown;
|
|
17
|
-
steps:
|
|
18
|
-
toolCalls?: {
|
|
19
|
-
name: string;
|
|
20
|
-
args: Record<string, unknown>;
|
|
21
|
-
result: string;
|
|
22
|
-
}[];
|
|
23
|
-
}[];
|
|
17
|
+
steps: Pick<AIAgentStep, 'toolCalls'>[];
|
|
24
18
|
}): Promise<string>;
|
|
25
19
|
export declare function trimMessages(messages: AIMessage[], maxTokenBudget?: number): AIMessage[];
|
|
26
20
|
export declare function parseWorkingMemory(text: string): Record<string, unknown> | null;
|
|
@@ -102,6 +102,7 @@ export async function saveMessages(storage, threadId, resourceId, memoryConfig,
|
|
|
102
102
|
id: toolCallIds[i],
|
|
103
103
|
name: tc.name,
|
|
104
104
|
result: tc.result,
|
|
105
|
+
...(tc.error ? { error: tc.error } : {}),
|
|
105
106
|
})),
|
|
106
107
|
createdAt: new Date(),
|
|
107
108
|
});
|
|
@@ -256,9 +257,39 @@ export function stripWorkingMemoryForStreaming(text) {
|
|
|
256
257
|
}
|
|
257
258
|
return output;
|
|
258
259
|
}
|
|
260
|
+
async function persistWorkingMemory(options, workingMemory) {
|
|
261
|
+
if (!options.storage)
|
|
262
|
+
return;
|
|
263
|
+
const existing = (await options.storage.getWorkingMemory(options.threadId, 'thread')) ?? {};
|
|
264
|
+
const merged = deepMergeWorkingMemory(existing, workingMemory);
|
|
265
|
+
if (options.schemaService && options.workingMemorySchemaName) {
|
|
266
|
+
try {
|
|
267
|
+
await options.schemaService.validateSchema(options.workingMemorySchemaName, merged);
|
|
268
|
+
}
|
|
269
|
+
catch (err) {
|
|
270
|
+
options.logger?.warn(`Working memory validation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
await options.storage.saveWorkingMemory(options.threadId, 'thread', merged);
|
|
275
|
+
}
|
|
259
276
|
export function createWorkingMemoryMiddleware(options) {
|
|
260
277
|
return {
|
|
261
278
|
modifyOutputStream: async (_services, { event, state }) => {
|
|
279
|
+
// A streamed step ends at its `usage` event, or at `done` for a model
|
|
280
|
+
// that reports no usage. That is the last moment the unstripped text is
|
|
281
|
+
// still reachable: it lives only in `state.rawText`, because the strip
|
|
282
|
+
// below runs before anything downstream — including the channel that
|
|
283
|
+
// accumulates what `modifyOutput` would later be handed.
|
|
284
|
+
if (event.type === 'usage' || event.type === 'done') {
|
|
285
|
+
const { workingMemory } = extractWorkingMemory(state.rawText ?? '');
|
|
286
|
+
state.rawText = '';
|
|
287
|
+
state.emittedVisibleText = '';
|
|
288
|
+
if (workingMemory) {
|
|
289
|
+
await persistWorkingMemory(options, workingMemory);
|
|
290
|
+
}
|
|
291
|
+
return event;
|
|
292
|
+
}
|
|
262
293
|
if (event.type !== 'text-delta')
|
|
263
294
|
return event;
|
|
264
295
|
const rawText = `${state.rawText ?? ''}${event.text}`;
|
|
@@ -275,24 +306,10 @@ export function createWorkingMemoryMiddleware(options) {
|
|
|
275
306
|
return null;
|
|
276
307
|
return { ...event, text: delta };
|
|
277
308
|
},
|
|
278
|
-
modifyOutput: async (_services, { text, messages
|
|
309
|
+
modifyOutput: async (_services, { text, messages }) => {
|
|
279
310
|
const { workingMemory, cleanedText } = extractWorkingMemory(text);
|
|
280
|
-
if (workingMemory
|
|
281
|
-
|
|
282
|
-
const merged = deepMergeWorkingMemory(existing, workingMemory);
|
|
283
|
-
let valid = true;
|
|
284
|
-
if (options.schemaService && options.workingMemorySchemaName) {
|
|
285
|
-
try {
|
|
286
|
-
await options.schemaService.validateSchema(options.workingMemorySchemaName, merged);
|
|
287
|
-
}
|
|
288
|
-
catch (err) {
|
|
289
|
-
valid = false;
|
|
290
|
-
options.logger?.warn(`Working memory validation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
if (valid) {
|
|
294
|
-
await options.storage.saveWorkingMemory(options.threadId, 'thread', merged);
|
|
295
|
-
}
|
|
311
|
+
if (workingMemory) {
|
|
312
|
+
await persistWorkingMemory(options, workingMemory);
|
|
296
313
|
}
|
|
297
314
|
return {
|
|
298
315
|
text: cleanedText,
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves a model name to a concrete `provider/model`. Aliases come from the
|
|
3
|
+
* `models` table in pikku.config.json; a name containing `/` is already
|
|
4
|
+
* concrete. Read from the main package, not the calling addon's — which model
|
|
5
|
+
* a tier points at is the hosting app's decision.
|
|
6
|
+
*/
|
|
7
|
+
export declare const resolveModelAlias: (model: string) => string;
|
|
1
8
|
export declare function resolveModelConfig(_agentName: string, agent: {
|
|
2
9
|
model: string;
|
|
3
10
|
temperature?: number;
|