@happyvertical/smrt-personas 0.38.26 → 0.39.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -30
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +2 -2
- package/dist/smrt-knowledge.json +4 -4
- package/package.json +22 -21
- package/LICENSE +0 -7
package/dist/index.d.ts
CHANGED
|
@@ -3,9 +3,9 @@ export { DirectiveActivationDeniedError, type DirectiveApprovalResult, Directive
|
|
|
3
3
|
export { ACTIVATE_DIRECTIVE_PERMISSION, DIRECTIVE_ACTIVATION_PERMISSION_DEF, type DirectivePrincipal, ensurePersonaPermissionsRegistered, principalFromPermissions, registerPersonaPermissions, resolveDirectivePrincipal, } from './directive-principal.js';
|
|
4
4
|
export { computeDirectiveFingerprint, type DirectiveEvidence, DirectiveProposal, DirectiveProposalCollection, type DirectiveProposalStatus, } from './directive-proposal.js';
|
|
5
5
|
export { Feedback, FeedbackCollection, type FeedbackOutcomeOptions, type FeedbackSignalType, type FeedbackSource, feedbackSourceFor, HUMAN_SIGNAL_TYPES, } from './feedback.js';
|
|
6
|
+
export { type AddPersonaInstanceOptions, addPersonaInstance, agentOptionsForPersona, type BuildPersonaInstanceAdminOptions, buildPersonaInstanceAdmin, DEFAULT_PERSONA_NAME, isDefaultPersona, type PersonaAgentOptions, type PersonaInstanceAdminView, type PersonaInstanceView, personaInstanceKey, removePersonaInstance, type SchedulePersonaInstanceOptions, schedulePersonaInstance, type UpgradeSingletonOptions, type UpgradeSingletonResult, upgradeSingletonToDefaultPersona, } from './persona-instance.js';
|
|
6
7
|
export { type PersonaMemoryLike, personaLearningMemory, personaMemoryScope, reinforceFromFeedback, } from './persona-memory.js';
|
|
7
8
|
export { applyPersonaInstructions, ensurePersonaInstructionsPrompt, type PersonaLike, personaInstructionsPromptKey, resolvePersonaInstructions, upsertPromptTemplateOverride, } from './persona-prompt.js';
|
|
8
|
-
export { type AddPersonaInstanceOptions, addPersonaInstance, agentOptionsForPersona, type BuildPersonaInstanceAdminOptions, buildPersonaInstanceAdmin, DEFAULT_PERSONA_NAME, isDefaultPersona, type PersonaAgentOptions, type PersonaInstanceAdminView, type PersonaInstanceView, personaInstanceKey, removePersonaInstance, type SchedulePersonaInstanceOptions, schedulePersonaInstance, type UpgradeSingletonOptions, type UpgradeSingletonResult, upgradeSingletonToDefaultPersona, } from './persona-instance.js';
|
|
9
9
|
export { availabilityFromResolvedAgent, type ManifestPersonaDefaults, type PersonaAvailabilityGate, type PersonaContext, PersonaResolver, type ResolvedPersona, type ResolvePersonaOptions, } from './persona-resolver.js';
|
|
10
10
|
export { type DirectiveDraft, type DirectiveReflector, type ReflectionInput, type ReflectionPersona, type ReflectionPersonaInput, ReflectionRunner, type ReflectionRunnerOptions, type ReflectionRunOptions, type ReflectionRunResult, } from './reflection-runner.js';
|
|
11
11
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,OAAO,wBAAwB,CAAC;AAIhC,OAAO,EACL,YAAY,EACZ,sBAAsB,EACtB,mBAAmB,EACnB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,8BAA8B,EAC9B,KAAK,uBAAuB,EAC5B,wBAAwB,EACxB,KAAK,+BAA+B,EACpC,wBAAwB,EACxB,KAAK,wBAAwB,EAC7B,KAAK,WAAW,GACjB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,6BAA6B,EAC7B,mCAAmC,EACnC,KAAK,kBAAkB,EACvB,kCAAkC,EAClC,wBAAwB,EACxB,0BAA0B,EAC1B,yBAAyB,GAC1B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,2BAA2B,EAC3B,KAAK,iBAAiB,EACtB,iBAAiB,EACjB,2BAA2B,EAC3B,KAAK,uBAAuB,GAC7B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,QAAQ,EACR,kBAAkB,EAClB,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,KAAK,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,OAAO,wBAAwB,CAAC;AAIhC,OAAO,EACL,YAAY,EACZ,sBAAsB,EACtB,mBAAmB,EACnB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,8BAA8B,EAC9B,KAAK,uBAAuB,EAC5B,wBAAwB,EACxB,KAAK,+BAA+B,EACpC,wBAAwB,EACxB,KAAK,wBAAwB,EAC7B,KAAK,WAAW,GACjB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,6BAA6B,EAC7B,mCAAmC,EACnC,KAAK,kBAAkB,EACvB,kCAAkC,EAClC,wBAAwB,EACxB,0BAA0B,EAC1B,yBAAyB,GAC1B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,2BAA2B,EAC3B,KAAK,iBAAiB,EACtB,iBAAiB,EACjB,2BAA2B,EAC3B,KAAK,uBAAuB,GAC7B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,QAAQ,EACR,kBAAkB,EAClB,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,KAAK,yBAAyB,EAC9B,kBAAkB,EAClB,sBAAsB,EACtB,KAAK,gCAAgC,EACrC,yBAAyB,EACzB,oBAAoB,EACpB,gBAAgB,EAChB,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAC7B,KAAK,mBAAmB,EACxB,kBAAkB,EAClB,qBAAqB,EACrB,KAAK,8BAA8B,EACnC,uBAAuB,EACvB,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,gCAAgC,GACjC,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,KAAK,iBAAiB,EACtB,qBAAqB,EACrB,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,wBAAwB,EACxB,+BAA+B,EAC/B,KAAK,WAAW,EAChB,4BAA4B,EAC5B,0BAA0B,EAC1B,4BAA4B,GAC7B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,6BAA6B,EAC7B,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,EAC5B,KAAK,cAAc,EACnB,eAAe,EACf,KAAK,eAAe,EACpB,KAAK,qBAAqB,GAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,EAC3B,gBAAgB,EAChB,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,GACzB,MAAM,wBAAwB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { TenantScoped, tenantId } from "@happyvertical/smrt-tenancy";
|
|
|
4
4
|
import { PromptOverrideCollection, PromptRegistry, definePrompt, resolvePrompt } from "@happyvertical/smrt-prompts";
|
|
5
5
|
import { instanceScopedSubscriber } from "@happyvertical/smrt-agents";
|
|
6
6
|
//#region src/__smrt-register__.ts
|
|
7
|
-
ObjectRegistry.registerPackageManifest(JSON.parse("{\"version\":\"1.0.0\",\"timestamp\":1783688086353,\"packageName\":\"@happyvertical/smrt-personas\",\"packageVersion\":\"0.38.26\",\"objects\":{\"@happyvertical/smrt-personas:AgentPersona\":{\"name\":\"agentpersona\",\"className\":\"AgentPersona\",\"qualifiedName\":\"@happyvertical/smrt-personas:AgentPersona\",\"collection\":\"agentpersonas\",\"filePath\":\"/home/runner/_work/smrt/smrt/packages/personas/src/agent-persona.ts\",\"packageName\":\"@happyvertical/smrt-personas\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"sqlType\":\"UUID\",\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":true,\"autoPopulate\":true,\"nullable\":false,\"mode\":\"required\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"agentClass\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"name\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"contextType\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true}},\"contextId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true}},\"instructions\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"allowedTools\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"runAsUserId\":{\"type\":\"crossPackageRef\",\"required\":true,\"related\":\"@happyvertical/smrt-users:User\"},\"actsAsProfileId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-profiles:Profile\",\"_meta\":{\"nullable\":true}},\"memoryScope\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"priority\":{\"type\":\"integer\",\"required\":false,\"default\":0},\"enabled\":{\"type\":\"boolean\",\"required\":false,\"_meta\":{}}},\"methods\":{\"getAllowedTools\":{\"name\":\"getAllowedTools\",\"async\":false,\"parameters\":[],\"returnType\":\"string[]\",\"isStatic\":false,\"isPublic\":true},\"setAllowedTools\":{\"name\":\"setAllowedTools\",\"async\":false,\"parameters\":[{\"name\":\"tools\",\"type\":\"string[]\",\"optional\":false}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"agent_personas\",\"api\":{\"include\":[\"list\",\"get\",\"create\",\"update\",\"delete\"]},\"cli\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"conflictColumns\":[\"tenant_id\",\"agent_class\",\"name\"],\"tenantScoped\":{\"mode\":\"required\"}},\"extends\":\"SmrtObject\",\"exportName\":\"AgentPersona\",\"collectionExportName\":\"AgentPersonaCollection\",\"validationRules\":[{\"field\":\"tenantId\",\"rule\":\"required\",\"fieldType\":\"text\"},{\"field\":\"runAsUserId\",\"rule\":\"required\",\"fieldType\":\"crossPackageRef\"}],\"schema\":{\"tableName\":\"agent_personas\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"agent_personas\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"agent_class\\\" TEXT,\\n \\\"name\\\" TEXT DEFAULT '',\\n \\\"context_type\\\" TEXT,\\n \\\"context_id\\\" TEXT,\\n \\\"instructions\\\" TEXT,\\n \\\"allowed_tools\\\" TEXT,\\n \\\"run_as_user_id\\\" UUID NOT NULL,\\n \\\"acts_as_profile_id\\\" UUID,\\n \\\"memory_scope\\\" TEXT,\\n \\\"priority\\\" INTEGER DEFAULT 0,\\n \\\"enabled\\\" BOOLEAN\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":true,\"unique\":false},\"agent_class\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"name\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"context_type\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"context_id\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"instructions\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"allowed_tools\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"run_as_user_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":true,\"unique\":false},\"acts_as_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"memory_scope\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"priority\":{\"type\":\"INTEGER\",\"notNull\":false,\"unique\":false,\"default\":0},\"enabled\":{\"type\":\"BOOLEAN\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"agent_personas_id_idx\",\"columns\":[\"id\"]},{\"name\":\"agent_personas_tenant_id_agent_class_idx\",\"columns\":[\"tenant_id\",\"agent_class\",\"name\"],\"unique\":true}],\"version\":\"71e955ef\"}},\"@happyvertical/smrt-personas:AgentPersonaCollection\":{\"name\":\"agentpersonacollection\",\"className\":\"AgentPersonaCollection\",\"qualifiedName\":\"@happyvertical/smrt-personas:AgentPersonaCollection\",\"collection\":\"agentpersonas\",\"filePath\":\"/home/runner/_work/smrt/smrt/packages/personas/src/agent-persona.ts\",\"packageName\":\"@happyvertical/smrt-personas\",\"fields\":{},\"methods\":{\"byTenantAndClass\":{\"name\":\"byTenantAndClass\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false},{\"name\":\"agentClass\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<AgentPersona[]>\",\"isStatic\":false,\"isPublic\":true},\"findActive\":{\"name\":\"findActive\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false},{\"name\":\"agentClass\",\"type\":\"string\",\"optional\":false},{\"name\":\"context\",\"type\":\"object\",\"optional\":true}],\"returnType\":\"Promise<AgentPersona[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"agent_personas\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"AgentPersona\",\"exportName\":\"AgentPersonaCollection\",\"collectionExportName\":\"AgentPersonaCollectionCollection\",\"schema\":{\"tableName\":\"agent_personas\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"agent_personas\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"}},\"indexes\":[{\"name\":\"agent_personas_id_idx\",\"columns\":[\"id\"]},{\"name\":\"agent_personas_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true}],\"version\":\"48e54c2f\"}},\"@happyvertical/smrt-personas:DirectiveProposal\":{\"name\":\"directiveproposal\",\"className\":\"DirectiveProposal\",\"qualifiedName\":\"@happyvertical/smrt-personas:DirectiveProposal\",\"collection\":\"directiveproposals\",\"filePath\":\"/home/runner/_work/smrt/smrt/packages/personas/src/directive-proposal.ts\",\"packageName\":\"@happyvertical/smrt-personas\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"sqlType\":\"UUID\",\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":true,\"autoPopulate\":true,\"nullable\":false,\"mode\":\"required\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"personaId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"AgentPersona\",\"_meta\":{\"required\":true}},\"agentClass\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"promptKey\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"proposedInstructions\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"currentInstructions\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"rationale\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"evidence\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"status\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"fingerprint\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"confidence\":{\"type\":\"decimal\",\"required\":false,\"default\":0},\"proposedBy\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"reviewedBy\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true}},\"reviewedAt\":{\"type\":\"datetime\",\"required\":false,\"_meta\":{\"nullable\":true}},\"reviewNote\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true}},\"activatedOverrideId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true}}},\"methods\":{\"getEvidence\":{\"name\":\"getEvidence\",\"async\":false,\"parameters\":[],\"returnType\":\"DirectiveEvidence\",\"isStatic\":false,\"isPublic\":true},\"setEvidence\":{\"name\":\"setEvidence\",\"async\":false,\"parameters\":[{\"name\":\"value\",\"type\":\"DirectiveEvidence\",\"optional\":false}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"isPending\":{\"name\":\"isPending\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"directive_proposals\",\"api\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"tenantScoped\":{\"mode\":\"required\"}},\"extends\":\"SmrtObject\",\"exportName\":\"DirectiveProposal\",\"collectionExportName\":\"DirectiveProposalCollection\",\"validationRules\":[{\"field\":\"tenantId\",\"rule\":\"required\",\"fieldType\":\"text\"},{\"field\":\"personaId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"}],\"schema\":{\"tableName\":\"directive_proposals\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"directive_proposals\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"persona_id\\\" UUID NOT NULL,\\n \\\"agent_class\\\" TEXT,\\n \\\"prompt_key\\\" TEXT,\\n \\\"proposed_instructions\\\" TEXT,\\n \\\"current_instructions\\\" TEXT,\\n \\\"rationale\\\" TEXT,\\n \\\"evidence\\\" TEXT,\\n \\\"status\\\" TEXT,\\n \\\"fingerprint\\\" TEXT,\\n \\\"confidence\\\" REAL DEFAULT 0,\\n \\\"proposed_by\\\" TEXT,\\n \\\"reviewed_by\\\" TEXT,\\n \\\"reviewed_at\\\" TIMESTAMP,\\n \\\"review_note\\\" TEXT,\\n \\\"activated_override_id\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":true,\"unique\":false},\"persona_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false},\"agent_class\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"prompt_key\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"proposed_instructions\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"current_instructions\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"rationale\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"evidence\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"status\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"fingerprint\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"confidence\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false,\"default\":0},\"proposed_by\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"reviewed_by\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"reviewed_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"review_note\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"activated_override_id\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"directive_proposals_id_idx\",\"columns\":[\"id\"]},{\"name\":\"directive_proposals_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true}],\"version\":\"4bd9414b\"}},\"@happyvertical/smrt-personas:DirectiveProposalCollection\":{\"name\":\"directiveproposalcollection\",\"className\":\"DirectiveProposalCollection\",\"qualifiedName\":\"@happyvertical/smrt-personas:DirectiveProposalCollection\",\"collection\":\"directiveproposals\",\"filePath\":\"/home/runner/_work/smrt/smrt/packages/personas/src/directive-proposal.ts\",\"packageName\":\"@happyvertical/smrt-personas\",\"fields\":{},\"methods\":{\"pending\":{\"name\":\"pending\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true}],\"returnType\":\"Promise<DirectiveProposal[]>\",\"isStatic\":false,\"isPublic\":true},\"findByFingerprint\":{\"name\":\"findByFingerprint\",\"async\":true,\"parameters\":[{\"name\":\"personaId\",\"type\":\"string\",\"optional\":false},{\"name\":\"fingerprint\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<DirectiveProposal[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"directive_proposals\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"DirectiveProposal\",\"exportName\":\"DirectiveProposalCollection\",\"collectionExportName\":\"DirectiveProposalCollectionCollection\",\"schema\":{\"tableName\":\"directive_proposals\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"directive_proposals\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"}},\"indexes\":[{\"name\":\"directive_proposals_id_idx\",\"columns\":[\"id\"]},{\"name\":\"directive_proposals_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true}],\"version\":\"f9669b44\"}},\"@happyvertical/smrt-personas:Feedback\":{\"name\":\"feedback\",\"className\":\"Feedback\",\"qualifiedName\":\"@happyvertical/smrt-personas:Feedback\",\"collection\":\"feedbacks\",\"filePath\":\"/home/runner/_work/smrt/smrt/packages/personas/src/feedback.ts\",\"packageName\":\"@happyvertical/smrt-personas\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"personaId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"AgentPersona\",\"_meta\":{\"required\":true}},\"agentClass\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"memoryScope\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"scope\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"key\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"signalType\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"source\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"correlationId\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"required\":true}},\"correlationType\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true}},\"rating\":{\"type\":\"decimal\",\"required\":false,\"_meta\":{\"nullable\":true}},\"metric\":{\"type\":\"decimal\",\"required\":false,\"_meta\":{\"nullable\":true}},\"success\":{\"type\":\"boolean\",\"required\":false,\"_meta\":{\"nullable\":true}},\"correction\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true}},\"comment\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true}},\"actorId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true}},\"metadata\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"reinforcedAt\":{\"type\":\"datetime\",\"required\":false,\"_meta\":{\"nullable\":true}}},\"methods\":{\"isHuman\":{\"name\":\"isHuman\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"getMetadata\":{\"name\":\"getMetadata\",\"async\":false,\"parameters\":[],\"returnType\":\"Record<string>\",\"isStatic\":false,\"isPublic\":true},\"setMetadata\":{\"name\":\"setMetadata\",\"async\":false,\"parameters\":[{\"name\":\"value\",\"type\":\"Record<string>\",\"optional\":false}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"updateMetadata\":{\"name\":\"updateMetadata\",\"async\":false,\"parameters\":[{\"name\":\"patch\",\"type\":\"Record<string>\",\"optional\":false}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"getCorrectionValue\":{\"name\":\"getCorrectionValue\",\"async\":false,\"parameters\":[],\"returnType\":\"string | undefined\",\"isStatic\":false,\"isPublic\":true},\"toLearningOutcome\":{\"name\":\"toLearningOutcome\",\"async\":false,\"parameters\":[{\"name\":\"options\",\"type\":\"FeedbackOutcomeOptions\",\"optional\":true}],\"returnType\":\"LearningOutcome | null\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"agent_feedback\",\"api\":{\"include\":[\"list\",\"get\",\"create\"]},\"cli\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"tenantScoped\":{\"mode\":\"optional\"}},\"extends\":\"SmrtObject\",\"exportName\":\"Feedback\",\"collectionExportName\":\"FeedbackCollection\",\"validationRules\":[{\"field\":\"personaId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"},{\"field\":\"correlationId\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"agent_feedback\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"agent_feedback\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"persona_id\\\" UUID NOT NULL,\\n \\\"agent_class\\\" TEXT,\\n \\\"memory_scope\\\" TEXT,\\n \\\"scope\\\" TEXT,\\n \\\"key\\\" TEXT,\\n \\\"signal_type\\\" TEXT,\\n \\\"source\\\" TEXT,\\n \\\"correlation_id\\\" TEXT NOT NULL,\\n \\\"correlation_type\\\" TEXT,\\n \\\"rating\\\" REAL,\\n \\\"metric\\\" REAL,\\n \\\"success\\\" BOOLEAN,\\n \\\"correction\\\" TEXT,\\n \\\"comment\\\" TEXT,\\n \\\"actor_id\\\" TEXT,\\n \\\"metadata\\\" TEXT,\\n \\\"reinforced_at\\\" TIMESTAMP\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"persona_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false},\"agent_class\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"memory_scope\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"scope\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"key\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"signal_type\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"source\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"correlation_id\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false},\"correlation_type\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"rating\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false},\"metric\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false},\"success\":{\"type\":\"BOOLEAN\",\"notNull\":false,\"unique\":false},\"correction\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"comment\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"actor_id\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"metadata\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"reinforced_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"agent_feedback_id_idx\",\"columns\":[\"id\"]},{\"name\":\"agent_feedback_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true}],\"version\":\"65f8e99e\"}},\"@happyvertical/smrt-personas:FeedbackCollection\":{\"name\":\"feedbackcollection\",\"className\":\"FeedbackCollection\",\"qualifiedName\":\"@happyvertical/smrt-personas:FeedbackCollection\",\"collection\":\"feedbacks\",\"filePath\":\"/home/runner/_work/smrt/smrt/packages/personas/src/feedback.ts\",\"packageName\":\"@happyvertical/smrt-personas\",\"fields\":{},\"methods\":{\"forPersona\":{\"name\":\"forPersona\",\"async\":true,\"parameters\":[{\"name\":\"personaId\",\"type\":\"string\",\"optional\":false},{\"name\":\"options\",\"type\":\"object\",\"optional\":true}],\"returnType\":\"Promise<Feedback[]>\",\"isStatic\":false,\"isPublic\":true},\"forScope\":{\"name\":\"forScope\",\"async\":true,\"parameters\":[{\"name\":\"memoryScope\",\"type\":\"string\",\"optional\":false},{\"name\":\"options\",\"type\":\"object\",\"optional\":true}],\"returnType\":\"Promise<Feedback[]>\",\"isStatic\":false,\"isPublic\":true},\"byCorrelation\":{\"name\":\"byCorrelation\",\"async\":true,\"parameters\":[{\"name\":\"correlationId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Feedback[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"agent_feedback\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"Feedback\",\"exportName\":\"FeedbackCollection\",\"collectionExportName\":\"FeedbackCollectionCollection\",\"schema\":{\"tableName\":\"agent_feedback\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"agent_feedback\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"}},\"indexes\":[{\"name\":\"agent_feedback_id_idx\",\"columns\":[\"id\"]},{\"name\":\"agent_feedback_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true}],\"version\":\"c8bb487d\"}}},\"moduleType\":\"smrt\",\"smrtDependencies\":[\"@happyvertical/smrt-agents\",\"@happyvertical/smrt-core\",\"@happyvertical/smrt-prompts\",\"@happyvertical/smrt-tenancy\",\"@happyvertical/smrt-users\"]}"));
|
|
7
|
+
ObjectRegistry.registerPackageManifest(JSON.parse("{\"version\":\"1.0.0\",\"timestamp\":1783721913682,\"packageName\":\"@happyvertical/smrt-personas\",\"packageVersion\":\"0.39.0\",\"objects\":{\"@happyvertical/smrt-personas:AgentPersona\":{\"name\":\"agentpersona\",\"className\":\"AgentPersona\",\"qualifiedName\":\"@happyvertical/smrt-personas:AgentPersona\",\"collection\":\"agentpersonas\",\"filePath\":\"/home/runner/_work/smrt/smrt/packages/personas/src/agent-persona.ts\",\"packageName\":\"@happyvertical/smrt-personas\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"sqlType\":\"UUID\",\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":true,\"autoPopulate\":true,\"nullable\":false,\"mode\":\"required\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"agentClass\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"name\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"contextType\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true}},\"contextId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true}},\"instructions\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"allowedTools\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"runAsUserId\":{\"type\":\"crossPackageRef\",\"required\":true,\"related\":\"@happyvertical/smrt-users:User\"},\"actsAsProfileId\":{\"type\":\"crossPackageRef\",\"required\":false,\"related\":\"@happyvertical/smrt-profiles:Profile\",\"_meta\":{\"nullable\":true}},\"memoryScope\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"priority\":{\"type\":\"integer\",\"required\":false,\"default\":0},\"enabled\":{\"type\":\"boolean\",\"required\":false,\"_meta\":{}}},\"methods\":{\"getAllowedTools\":{\"name\":\"getAllowedTools\",\"async\":false,\"parameters\":[],\"returnType\":\"string[]\",\"isStatic\":false,\"isPublic\":true},\"setAllowedTools\":{\"name\":\"setAllowedTools\",\"async\":false,\"parameters\":[{\"name\":\"tools\",\"type\":\"string[]\",\"optional\":false}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"agent_personas\",\"api\":{\"include\":[\"list\",\"get\",\"create\",\"update\",\"delete\"]},\"cli\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"conflictColumns\":[\"tenant_id\",\"agent_class\",\"name\"],\"tenantScoped\":{\"mode\":\"required\"}},\"extends\":\"SmrtObject\",\"exportName\":\"AgentPersona\",\"collectionExportName\":\"AgentPersonaCollection\",\"validationRules\":[{\"field\":\"tenantId\",\"rule\":\"required\",\"fieldType\":\"text\"},{\"field\":\"runAsUserId\",\"rule\":\"required\",\"fieldType\":\"crossPackageRef\"}],\"schema\":{\"tableName\":\"agent_personas\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"agent_personas\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"agent_class\\\" TEXT,\\n \\\"name\\\" TEXT DEFAULT '',\\n \\\"context_type\\\" TEXT,\\n \\\"context_id\\\" TEXT,\\n \\\"instructions\\\" TEXT,\\n \\\"allowed_tools\\\" TEXT,\\n \\\"run_as_user_id\\\" UUID NOT NULL,\\n \\\"acts_as_profile_id\\\" UUID,\\n \\\"memory_scope\\\" TEXT,\\n \\\"priority\\\" INTEGER DEFAULT 0,\\n \\\"enabled\\\" BOOLEAN\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":true,\"unique\":false},\"agent_class\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"name\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"context_type\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"context_id\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"instructions\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"allowed_tools\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"run_as_user_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":true,\"unique\":false},\"acts_as_profile_id\":{\"type\":\"UUID\",\"referenceKind\":\"crossPackageRef\",\"notNull\":false,\"unique\":false},\"memory_scope\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"priority\":{\"type\":\"INTEGER\",\"notNull\":false,\"unique\":false,\"default\":0},\"enabled\":{\"type\":\"BOOLEAN\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"agent_personas_id_idx\",\"columns\":[\"id\"]},{\"name\":\"agent_personas_tenant_id_agent_class_idx\",\"columns\":[\"tenant_id\",\"agent_class\",\"name\"],\"unique\":true}],\"version\":\"71e955ef\"}},\"@happyvertical/smrt-personas:AgentPersonaCollection\":{\"name\":\"agentpersonacollection\",\"className\":\"AgentPersonaCollection\",\"qualifiedName\":\"@happyvertical/smrt-personas:AgentPersonaCollection\",\"collection\":\"agentpersonas\",\"filePath\":\"/home/runner/_work/smrt/smrt/packages/personas/src/agent-persona.ts\",\"packageName\":\"@happyvertical/smrt-personas\",\"fields\":{},\"methods\":{\"byTenantAndClass\":{\"name\":\"byTenantAndClass\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false},{\"name\":\"agentClass\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<AgentPersona[]>\",\"isStatic\":false,\"isPublic\":true},\"findActive\":{\"name\":\"findActive\",\"async\":true,\"parameters\":[{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false},{\"name\":\"agentClass\",\"type\":\"string\",\"optional\":false},{\"name\":\"context\",\"type\":\"object\",\"optional\":true}],\"returnType\":\"Promise<AgentPersona[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"agent_personas\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"AgentPersona\",\"exportName\":\"AgentPersonaCollection\",\"collectionExportName\":\"AgentPersonaCollectionCollection\",\"schema\":{\"tableName\":\"agent_personas\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"agent_personas\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"}},\"indexes\":[{\"name\":\"agent_personas_id_idx\",\"columns\":[\"id\"]},{\"name\":\"agent_personas_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true}],\"version\":\"48e54c2f\"}},\"@happyvertical/smrt-personas:DirectiveProposal\":{\"name\":\"directiveproposal\",\"className\":\"DirectiveProposal\",\"qualifiedName\":\"@happyvertical/smrt-personas:DirectiveProposal\",\"collection\":\"directiveproposals\",\"filePath\":\"/home/runner/_work/smrt/smrt/packages/personas/src/directive-proposal.ts\",\"packageName\":\"@happyvertical/smrt-personas\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"sqlType\":\"UUID\",\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":true,\"autoPopulate\":true,\"nullable\":false,\"mode\":\"required\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"personaId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"AgentPersona\",\"_meta\":{\"required\":true}},\"agentClass\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"promptKey\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"proposedInstructions\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"currentInstructions\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"rationale\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"evidence\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"status\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"fingerprint\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"confidence\":{\"type\":\"decimal\",\"required\":false,\"default\":0},\"proposedBy\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"reviewedBy\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true}},\"reviewedAt\":{\"type\":\"datetime\",\"required\":false,\"_meta\":{\"nullable\":true}},\"reviewNote\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true}},\"activatedOverrideId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true}}},\"methods\":{\"getEvidence\":{\"name\":\"getEvidence\",\"async\":false,\"parameters\":[],\"returnType\":\"DirectiveEvidence\",\"isStatic\":false,\"isPublic\":true},\"setEvidence\":{\"name\":\"setEvidence\",\"async\":false,\"parameters\":[{\"name\":\"value\",\"type\":\"DirectiveEvidence\",\"optional\":false}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"isPending\":{\"name\":\"isPending\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"directive_proposals\",\"api\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"tenantScoped\":{\"mode\":\"required\"}},\"extends\":\"SmrtObject\",\"exportName\":\"DirectiveProposal\",\"collectionExportName\":\"DirectiveProposalCollection\",\"validationRules\":[{\"field\":\"tenantId\",\"rule\":\"required\",\"fieldType\":\"text\"},{\"field\":\"personaId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"}],\"schema\":{\"tableName\":\"directive_proposals\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"directive_proposals\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID NOT NULL,\\n \\\"persona_id\\\" UUID NOT NULL,\\n \\\"agent_class\\\" TEXT,\\n \\\"prompt_key\\\" TEXT,\\n \\\"proposed_instructions\\\" TEXT,\\n \\\"current_instructions\\\" TEXT,\\n \\\"rationale\\\" TEXT,\\n \\\"evidence\\\" TEXT,\\n \\\"status\\\" TEXT,\\n \\\"fingerprint\\\" TEXT,\\n \\\"confidence\\\" REAL DEFAULT 0,\\n \\\"proposed_by\\\" TEXT,\\n \\\"reviewed_by\\\" TEXT,\\n \\\"reviewed_at\\\" TIMESTAMP,\\n \\\"review_note\\\" TEXT,\\n \\\"activated_override_id\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":true,\"unique\":false},\"persona_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false},\"agent_class\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"prompt_key\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"proposed_instructions\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"current_instructions\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"rationale\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"evidence\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"status\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"fingerprint\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"confidence\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false,\"default\":0},\"proposed_by\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"reviewed_by\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"reviewed_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false},\"review_note\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"activated_override_id\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"directive_proposals_id_idx\",\"columns\":[\"id\"]},{\"name\":\"directive_proposals_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true}],\"version\":\"4bd9414b\"}},\"@happyvertical/smrt-personas:DirectiveProposalCollection\":{\"name\":\"directiveproposalcollection\",\"className\":\"DirectiveProposalCollection\",\"qualifiedName\":\"@happyvertical/smrt-personas:DirectiveProposalCollection\",\"collection\":\"directiveproposals\",\"filePath\":\"/home/runner/_work/smrt/smrt/packages/personas/src/directive-proposal.ts\",\"packageName\":\"@happyvertical/smrt-personas\",\"fields\":{},\"methods\":{\"pending\":{\"name\":\"pending\",\"async\":true,\"parameters\":[{\"name\":\"options\",\"type\":\"object\",\"optional\":true}],\"returnType\":\"Promise<DirectiveProposal[]>\",\"isStatic\":false,\"isPublic\":true},\"findByFingerprint\":{\"name\":\"findByFingerprint\",\"async\":true,\"parameters\":[{\"name\":\"personaId\",\"type\":\"string\",\"optional\":false},{\"name\":\"fingerprint\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<DirectiveProposal[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"directive_proposals\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"DirectiveProposal\",\"exportName\":\"DirectiveProposalCollection\",\"collectionExportName\":\"DirectiveProposalCollectionCollection\",\"schema\":{\"tableName\":\"directive_proposals\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"directive_proposals\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"}},\"indexes\":[{\"name\":\"directive_proposals_id_idx\",\"columns\":[\"id\"]},{\"name\":\"directive_proposals_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true}],\"version\":\"f9669b44\"}},\"@happyvertical/smrt-personas:Feedback\":{\"name\":\"feedback\",\"className\":\"Feedback\",\"qualifiedName\":\"@happyvertical/smrt-personas:Feedback\",\"collection\":\"feedbacks\",\"filePath\":\"/home/runner/_work/smrt/smrt/packages/personas/src/feedback.ts\",\"packageName\":\"@happyvertical/smrt-personas\",\"fields\":{\"tenantId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"sqlType\":\"UUID\",\"nullable\":true,\"__tenancy\":{\"isTenantIdField\":true,\"autoFilter\":true,\"required\":false,\"autoPopulate\":true,\"nullable\":true,\"mode\":\"optional\",\"field\":\"tenantId\",\"allowSuperAdminBypass\":false}}},\"personaId\":{\"type\":\"foreignKey\",\"required\":true,\"related\":\"AgentPersona\",\"_meta\":{\"required\":true}},\"agentClass\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"memoryScope\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"scope\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"key\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"signalType\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"source\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"correlationId\":{\"type\":\"text\",\"required\":true,\"_meta\":{\"required\":true}},\"correlationType\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true}},\"rating\":{\"type\":\"decimal\",\"required\":false,\"_meta\":{\"nullable\":true}},\"metric\":{\"type\":\"decimal\",\"required\":false,\"_meta\":{\"nullable\":true}},\"success\":{\"type\":\"boolean\",\"required\":false,\"_meta\":{\"nullable\":true}},\"correction\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true}},\"comment\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true}},\"actorId\":{\"type\":\"text\",\"required\":false,\"_meta\":{\"nullable\":true}},\"metadata\":{\"type\":\"text\",\"required\":false,\"_meta\":{}},\"reinforcedAt\":{\"type\":\"datetime\",\"required\":false,\"_meta\":{\"nullable\":true}}},\"methods\":{\"isHuman\":{\"name\":\"isHuman\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"getMetadata\":{\"name\":\"getMetadata\",\"async\":false,\"parameters\":[],\"returnType\":\"Record<string>\",\"isStatic\":false,\"isPublic\":true},\"setMetadata\":{\"name\":\"setMetadata\",\"async\":false,\"parameters\":[{\"name\":\"value\",\"type\":\"Record<string>\",\"optional\":false}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"updateMetadata\":{\"name\":\"updateMetadata\",\"async\":false,\"parameters\":[{\"name\":\"patch\",\"type\":\"Record<string>\",\"optional\":false}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true},\"getCorrectionValue\":{\"name\":\"getCorrectionValue\",\"async\":false,\"parameters\":[],\"returnType\":\"string | undefined\",\"isStatic\":false,\"isPublic\":true},\"toLearningOutcome\":{\"name\":\"toLearningOutcome\",\"async\":false,\"parameters\":[{\"name\":\"options\",\"type\":\"FeedbackOutcomeOptions\",\"optional\":true}],\"returnType\":\"LearningOutcome | null\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"agent_feedback\",\"api\":{\"include\":[\"list\",\"get\",\"create\"]},\"cli\":{\"include\":[\"list\",\"get\"]},\"mcp\":{\"include\":[\"list\",\"get\"]},\"tenantScoped\":{\"mode\":\"optional\"}},\"extends\":\"SmrtObject\",\"exportName\":\"Feedback\",\"collectionExportName\":\"FeedbackCollection\",\"validationRules\":[{\"field\":\"personaId\",\"rule\":\"required\",\"fieldType\":\"foreignKey\"},{\"field\":\"correlationId\",\"rule\":\"required\",\"fieldType\":\"text\"}],\"schema\":{\"tableName\":\"agent_feedback\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"agent_feedback\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"tenant_id\\\" UUID,\\n \\\"persona_id\\\" UUID NOT NULL,\\n \\\"agent_class\\\" TEXT,\\n \\\"memory_scope\\\" TEXT,\\n \\\"scope\\\" TEXT,\\n \\\"key\\\" TEXT,\\n \\\"signal_type\\\" TEXT,\\n \\\"source\\\" TEXT,\\n \\\"correlation_id\\\" TEXT NOT NULL,\\n \\\"correlation_type\\\" TEXT,\\n \\\"rating\\\" REAL,\\n \\\"metric\\\" REAL,\\n \\\"success\\\" BOOLEAN,\\n \\\"correction\\\" TEXT,\\n \\\"comment\\\" TEXT,\\n \\\"actor_id\\\" TEXT,\\n \\\"metadata\\\" TEXT,\\n \\\"reinforced_at\\\" TIMESTAMP\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"tenant_id\":{\"type\":\"UUID\",\"referenceKind\":\"tenantId\",\"notNull\":false,\"unique\":false},\"persona_id\":{\"type\":\"UUID\",\"referenceKind\":\"foreignKey\",\"notNull\":true,\"unique\":false},\"agent_class\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"memory_scope\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"scope\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"key\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"signal_type\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"source\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"correlation_id\":{\"type\":\"TEXT\",\"notNull\":true,\"unique\":false},\"correlation_type\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"rating\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false},\"metric\":{\"type\":\"REAL\",\"notNull\":false,\"unique\":false},\"success\":{\"type\":\"BOOLEAN\",\"notNull\":false,\"unique\":false},\"correction\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"comment\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"actor_id\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"metadata\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"reinforced_at\":{\"type\":\"TIMESTAMP\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"agent_feedback_id_idx\",\"columns\":[\"id\"]},{\"name\":\"agent_feedback_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true}],\"version\":\"65f8e99e\"}},\"@happyvertical/smrt-personas:FeedbackCollection\":{\"name\":\"feedbackcollection\",\"className\":\"FeedbackCollection\",\"qualifiedName\":\"@happyvertical/smrt-personas:FeedbackCollection\",\"collection\":\"feedbacks\",\"filePath\":\"/home/runner/_work/smrt/smrt/packages/personas/src/feedback.ts\",\"packageName\":\"@happyvertical/smrt-personas\",\"fields\":{},\"methods\":{\"forPersona\":{\"name\":\"forPersona\",\"async\":true,\"parameters\":[{\"name\":\"personaId\",\"type\":\"string\",\"optional\":false},{\"name\":\"options\",\"type\":\"object\",\"optional\":true}],\"returnType\":\"Promise<Feedback[]>\",\"isStatic\":false,\"isPublic\":true},\"forScope\":{\"name\":\"forScope\",\"async\":true,\"parameters\":[{\"name\":\"memoryScope\",\"type\":\"string\",\"optional\":false},{\"name\":\"options\",\"type\":\"object\",\"optional\":true}],\"returnType\":\"Promise<Feedback[]>\",\"isStatic\":false,\"isPublic\":true},\"byCorrelation\":{\"name\":\"byCorrelation\",\"async\":true,\"parameters\":[{\"name\":\"correlationId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<Feedback[]>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"agent_feedback\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"Feedback\",\"exportName\":\"FeedbackCollection\",\"collectionExportName\":\"FeedbackCollectionCollection\",\"schema\":{\"tableName\":\"agent_feedback\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"agent_feedback\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"}},\"indexes\":[{\"name\":\"agent_feedback_id_idx\",\"columns\":[\"id\"]},{\"name\":\"agent_feedback_slug_context_idx\",\"columns\":[\"slug\",\"context\"],\"unique\":true}],\"version\":\"c8bb487d\"}}},\"moduleType\":\"smrt\",\"smrtDependencies\":[\"@happyvertical/smrt-agents\",\"@happyvertical/smrt-core\",\"@happyvertical/smrt-prompts\",\"@happyvertical/smrt-tenancy\",\"@happyvertical/smrt-users\"]}"));
|
|
8
8
|
//#endregion
|
|
9
9
|
//#region src/directive-principal.ts
|
|
10
10
|
var ACTIVATE_DIRECTIVE_PERMISSION = "personas.activate-directive";
|
|
@@ -709,35 +709,6 @@ var DirectiveApprovalService = class {
|
|
|
709
709
|
}
|
|
710
710
|
};
|
|
711
711
|
//#endregion
|
|
712
|
-
//#region src/persona-memory.ts
|
|
713
|
-
function personaMemoryScope(persona) {
|
|
714
|
-
const explicit = persona.memoryScope?.trim();
|
|
715
|
-
if (explicit) return explicit;
|
|
716
|
-
if (persona.id) return `persona:${persona.id}`;
|
|
717
|
-
throw new Error("personaMemoryScope requires a persona with a memoryScope or an id");
|
|
718
|
-
}
|
|
719
|
-
function personaLearningMemory(options) {
|
|
720
|
-
const ownerClass = options.ownerClass ?? (options.persona.agentClass?.trim() || "AgentPersona");
|
|
721
|
-
return new LearningMemory({
|
|
722
|
-
db: options.db,
|
|
723
|
-
ownerClass,
|
|
724
|
-
ownerId: personaMemoryScope(options.persona),
|
|
725
|
-
tenantId: options.tenantId ?? options.persona.tenantId ?? null,
|
|
726
|
-
semanticSearch: options.semanticSearch,
|
|
727
|
-
config: options.config
|
|
728
|
-
});
|
|
729
|
-
}
|
|
730
|
-
async function reinforceFromFeedback(memory, feedback, options = {}) {
|
|
731
|
-
const outcome = feedback.toLearningOutcome(options);
|
|
732
|
-
if (!outcome) return null;
|
|
733
|
-
const value = feedback.getCorrectionValue();
|
|
734
|
-
return memory.capture({
|
|
735
|
-
scope: feedback.scope,
|
|
736
|
-
key: feedback.key,
|
|
737
|
-
...value !== void 0 ? { value } : {}
|
|
738
|
-
}, outcome);
|
|
739
|
-
}
|
|
740
|
-
//#endregion
|
|
741
712
|
//#region src/persona-instance.ts
|
|
742
713
|
var DEFAULT_PERSONA_NAME = "default";
|
|
743
714
|
function personaInstanceKey(persona) {
|
|
@@ -851,6 +822,35 @@ async function upgradeSingletonToDefaultPersona(personas, options) {
|
|
|
851
822
|
};
|
|
852
823
|
}
|
|
853
824
|
//#endregion
|
|
825
|
+
//#region src/persona-memory.ts
|
|
826
|
+
function personaMemoryScope(persona) {
|
|
827
|
+
const explicit = persona.memoryScope?.trim();
|
|
828
|
+
if (explicit) return explicit;
|
|
829
|
+
if (persona.id) return `persona:${persona.id}`;
|
|
830
|
+
throw new Error("personaMemoryScope requires a persona with a memoryScope or an id");
|
|
831
|
+
}
|
|
832
|
+
function personaLearningMemory(options) {
|
|
833
|
+
const ownerClass = options.ownerClass ?? (options.persona.agentClass?.trim() || "AgentPersona");
|
|
834
|
+
return new LearningMemory({
|
|
835
|
+
db: options.db,
|
|
836
|
+
ownerClass,
|
|
837
|
+
ownerId: personaMemoryScope(options.persona),
|
|
838
|
+
tenantId: options.tenantId ?? options.persona.tenantId ?? null,
|
|
839
|
+
semanticSearch: options.semanticSearch,
|
|
840
|
+
config: options.config
|
|
841
|
+
});
|
|
842
|
+
}
|
|
843
|
+
async function reinforceFromFeedback(memory, feedback, options = {}) {
|
|
844
|
+
const outcome = feedback.toLearningOutcome(options);
|
|
845
|
+
if (!outcome) return null;
|
|
846
|
+
const value = feedback.getCorrectionValue();
|
|
847
|
+
return memory.capture({
|
|
848
|
+
scope: feedback.scope,
|
|
849
|
+
key: feedback.key,
|
|
850
|
+
...value !== void 0 ? { value } : {}
|
|
851
|
+
}, outcome);
|
|
852
|
+
}
|
|
853
|
+
//#endregion
|
|
854
854
|
//#region src/persona-resolver.ts
|
|
855
855
|
function availabilityFromResolvedAgent(resolved, options = {}) {
|
|
856
856
|
if (!resolved) return null;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["tenantId"],"sources":["../src/__smrt-register__.ts","../src/directive-principal.ts","../src/agent-persona.ts","../src/directive-proposal.ts","../src/feedback.ts","../src/persona-prompt.ts","../src/directive-approval.ts","../src/persona-memory.ts","../src/persona-instance.ts","../src/persona-resolver.ts","../src/reflection-runner.ts","../src/index.ts"],"sourcesContent":["import { ObjectRegistry } from '@happyvertical/smrt-core';\n\nObjectRegistry.registerPackageManifest(\n new URL('./manifest.json', import.meta.url),\n);\n","/**\n * The permission split that gates persona directive activation (#1889).\n *\n * **The gate is the permission system, not a bespoke subsystem.** Activating a\n * directive — writing/enabling the persona-scoped `prompt_override` — is a\n * permissioned operation guarded by the `personas.activate-directive` slug. The\n * autonomous reflection principal runs *without* that permission, so it can only\n * propose; a human who holds it approves / edits / rejects. Confidence-only\n * reinforcement stays automatic; only instruction rewrites are gated.\n *\n * This module contributes the slug to the manifest-derived permission catalog\n * (via `registerPermissionDefinitions`) and provides a small\n * {@link DirectivePrincipal} abstraction over \"which permission slugs does this\n * actor hold\". In production the principal is built from a\n * `PermissionResolver.resolvePermissions()` result; tests inject one directly.\n *\n * @module\n */\n\nimport {\n type PermissionDefinition,\n type PermissionResolver,\n registerPermissionDefinitions,\n} from '@happyvertical/smrt-users';\n\n/** The permission slug that authorises activating a persona directive. */\nexport const ACTIVATE_DIRECTIVE_PERMISSION = 'personas.activate-directive';\n\n/** Catalog definition contributed for {@link ACTIVATE_DIRECTIVE_PERMISSION}. */\nexport const DIRECTIVE_ACTIVATION_PERMISSION_DEF: PermissionDefinition = {\n slug: ACTIVATE_DIRECTIVE_PERMISSION,\n category: 'personas',\n name: 'Activate Persona Directive',\n description:\n \"Approve, edit, or reject a proposed edit to a persona's instructions and activate the persona-scoped prompt override\",\n};\n\n/**\n * An actor whose authority is expressed as a set of held permission slugs.\n *\n * Deliberately minimal so the gate depends only on the permission model, not on\n * any particular resolver or session machinery.\n */\nexport interface DirectivePrincipal {\n /** Optional stable id (recorded as the reviewer on approve/reject). */\n readonly id?: string;\n /**\n * The tenant this principal's authority was resolved for. Permissions are\n * resolved per tenant (`PermissionResolver.resolvePermissions(userId, tenantId)`),\n * so a principal authorised in one tenant must not activate another tenant's\n * directive. When set, the approval service enforces\n * `principal.tenantId === proposal.tenantId`. `undefined` skips the check\n * (e.g. a system/global actor or a hand-built principal).\n */\n readonly tenantId?: string;\n /** Whether this actor holds the given permission slug. */\n can(slug: string): boolean;\n}\n\n/**\n * Build a {@link DirectivePrincipal} from an explicit set of granted slugs.\n */\nexport function principalFromPermissions(\n permissions: Iterable<string>,\n options: { id?: string; tenantId?: string } = {},\n): DirectivePrincipal {\n const granted = new Set(permissions);\n return {\n id: options.id,\n tenantId: options.tenantId,\n can: (slug: string) => granted.has(slug),\n };\n}\n\n/**\n * Build a {@link DirectivePrincipal} for a user in a tenant by resolving their\n * effective permissions through the RBAC {@link PermissionResolver} — the\n * production wiring that makes the gate concretely the permission system.\n */\nexport async function resolveDirectivePrincipal(options: {\n resolver: PermissionResolver;\n userId: string;\n tenantId: string;\n}): Promise<DirectivePrincipal> {\n const { permissions } = await options.resolver.resolvePermissions(\n options.userId,\n options.tenantId,\n );\n // Carry the resolved tenant so the approval service can refuse a directive\n // from a different tenant (permissions were resolved for this tenant only).\n return principalFromPermissions(permissions, {\n id: options.userId,\n tenantId: options.tenantId,\n });\n}\n\nlet personaPermissionsRegistered = false;\n\n/**\n * Register the persona directive-activation permission into the runtime catalog.\n *\n * @returns An unregister function (primarily for tests).\n */\nexport function registerPersonaPermissions(): () => void {\n return registerPermissionDefinitions([DIRECTIVE_ACTIVATION_PERMISSION_DEF]);\n}\n\n/**\n * Register the persona permissions once per process. Called as a side effect\n * from the package entry so the slug is present in the permission catalog for\n * any consumer that imports `@happyvertical/smrt-personas`.\n */\nexport function ensurePersonaPermissionsRegistered(): void {\n if (personaPermissionsRegistered) {\n return;\n }\n personaPermissionsRegistered = true;\n registerPersonaPermissions();\n}\n","/**\n * AgentPersona - Tenant-owned, context-scoped persona for an agent class.\n *\n * A persona layers behavioral configuration on top of a {@link TenantAgent}\n * binding (from `@happyvertical/smrt-agents`). Where `TenantAgent` answers\n * \"is this agent available for the tenant, and what is its capability ceiling\",\n * an `AgentPersona` answers \"how should this agent behave for this tenant in\n * this context\" — its instructions, allowed tools, run-as principal, acting\n * identity, and memory scope.\n *\n * There can be many personas per `(tenant, agentClass)` — one per context\n * (e.g. a site, property, or chat room) plus optional tenant-wide defaults.\n * Personas are unique on `(tenant_id, agent_class, name)`.\n *\n * Resolution (context + hierarchy + priority) lives in {@link PersonaResolver};\n * this class is the persisted record and its CRUD collection only.\n */\n\nimport {\n crossPackageRef,\n field,\n getClassName,\n ObjectRegistry,\n SmrtCollection,\n SmrtObject,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\n\n/**\n * Return the canonical agent type identifier for storage and lookup.\n *\n * Uses the registry's qualified name when the class is registered and falls\n * back to the raw input for dynamically defined or unregistered classes. This\n * mirrors `getAgentTypeName()` in `@happyvertical/smrt-agents` without reaching\n * into that package's internal module — personas store the same canonical form\n * that `TenantAgent` does so the two layers line up.\n */\nexport function canonicalAgentClass(name: string): string {\n const registered = ObjectRegistry.getClass(name);\n return registered?.qualifiedName || registered?.name || name;\n}\n\n/**\n * Return the meaningful aliases for an agent class — the canonical qualified\n * name plus the simple class name — deduplicated.\n *\n * Lookups match against both so a persona persisted under a simple name (e.g.\n * `Praeco`, when written through the generated create API without\n * normalization) is still found when resolving under the canonical qualified\n * name, and vice versa. Mirrors `getAgentTypeAliases()` in\n * `@happyvertical/smrt-agents`.\n */\nexport function agentClassAliases(name: string): string[] {\n const registered = ObjectRegistry.getClass(name);\n const canonical = registered?.qualifiedName || registered?.name || name;\n const simple = registered?.name || getClassName(name);\n return Array.from(new Set([canonical, simple].filter(Boolean)));\n}\n\n/**\n * Parse a JSON-array-of-strings stored as text, tolerating malformed input.\n */\nfunction parseStringArray(raw: string | null | undefined): string[] {\n if (!raw) {\n return [];\n }\n try {\n const parsed = JSON.parse(raw);\n return Array.isArray(parsed)\n ? parsed.filter((value): value is string => typeof value === 'string')\n : [];\n } catch {\n return [];\n }\n}\n\n/**\n * AgentPersona SmrtObject — a tenant/context-scoped behavioral profile for an\n * agent class.\n */\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'agent_personas',\n api: { include: ['list', 'get', 'create', 'update', 'delete'] },\n cli: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n conflictColumns: ['tenant_id', 'agent_class', 'name'],\n})\nexport class AgentPersona extends SmrtObject {\n /** Owning tenant (required — personas are never global). */\n @tenantId()\n tenantId: string = '';\n\n /**\n * Canonical qualified agent type this persona configures\n * (e.g. `@happyvertical/smrt-agents:Praeco`). Stored in canonical form so it\n * lines up with `TenantAgent.agentClass`.\n */\n @field({ type: 'text' })\n agentClass: string = '';\n\n /**\n * Human-readable persona name, unique per `(tenant, agentClass)`\n * (see `conflictColumns`). Inherited `name` from {@link SmrtObject} is the\n * conflict column; declared here for documentation and typing clarity.\n */\n name: string = '';\n\n /**\n * Optional context dimension type this persona is scoped to\n * (e.g. `'site'`, `'property'`, `'chatRoom'`). `null` means the persona is a\n * tenant-wide default that applies to every context for its agent class.\n */\n @field({ type: 'text', nullable: true })\n contextType: string | null = null;\n\n /**\n * Optional context dimension id. Only meaningful alongside `contextType`:\n * when set, the persona targets one specific context row; when `null` (with\n * a `contextType` set) it applies to every context of that type.\n */\n @field({ type: 'text', nullable: true })\n contextId: string | null = null;\n\n /** System prompt / behavioral instructions layered onto the agent. */\n @field({ type: 'text' })\n instructions: string = '';\n\n /**\n * Allowed tool identifiers, stored as a JSON array string. Use\n * {@link getAllowedTools} / {@link setAllowedTools} rather than reading this\n * field directly. Empty array (`'[]'`) means \"no persona-specific tools\"\n * (the resolver then falls back to manifest defaults, capped by the\n * `TenantAgent` ceiling).\n */\n @field({ type: 'text' })\n allowedTools: string = '[]';\n\n /**\n * The user whose principal this persona runs as (cross-package reference to\n * `@happyvertical/smrt-users:User`). Required — a persona always runs as a\n * concrete principal. Stored as a plain id column; no DDL FK constraint is\n * emitted (cross-package).\n */\n @crossPackageRef('@happyvertical/smrt-users:User', { required: true })\n runAsUserId: string = '';\n\n /**\n * Optional `Bot` profile the persona acts as for identity/audit\n * (cross-package reference to `@happyvertical/smrt-profiles:Profile`).\n * `null` when the persona has no distinct acting identity.\n */\n @crossPackageRef('@happyvertical/smrt-profiles:Profile', { nullable: true })\n actsAsProfileId: string | null = null;\n\n /**\n * Memory scope key controlling how the agent's memory/reflection is\n * partitioned for this persona. Empty string means \"use a resolver-derived\n * default\".\n */\n @field({ type: 'text' })\n memoryScope: string = '';\n\n /**\n * Resolution priority — higher wins when several personas apply to the same\n * context at the same tenant level. Integer.\n */\n priority: number = 0;\n\n /** Whether this persona is active and eligible for resolution. */\n @field({ type: 'boolean' })\n enabled: boolean = true;\n\n /**\n * Allowed tool identifiers as an array.\n *\n * Tolerates malformed stored JSON by returning an empty array.\n */\n getAllowedTools(): string[] {\n return parseStringArray(this.allowedTools);\n }\n\n /**\n * Replace the allowed tool identifiers.\n */\n setAllowedTools(tools: string[]): void {\n this.allowedTools = JSON.stringify(tools ?? []);\n }\n}\n\n/**\n * Collection for managing {@link AgentPersona} records.\n */\nexport class AgentPersonaCollection extends SmrtCollection<AgentPersona> {\n static readonly _itemClass = AgentPersona;\n\n /**\n * List personas for a tenant + agent class, matching either the canonical\n * qualified name or the simple class name (see {@link agentClassAliases}).\n *\n * Ordered by descending priority then name.\n *\n * @param extraWhere - Additional equality filters merged into the query\n * (e.g. `{ enabled: true }`).\n */\n private async listForClass(\n tenantId: string,\n agentClass: string,\n extraWhere: Record<string, unknown> = {},\n ): Promise<AgentPersona[]> {\n const aliases = agentClassAliases(agentClass);\n const where =\n aliases.length > 1\n ? { tenantId, 'agentClass in': aliases, ...extraWhere }\n : { tenantId, agentClass: aliases[0], ...extraWhere };\n const personas = await this.list({ where });\n return sortByPriorityThenName(personas);\n }\n\n /**\n * List every persona bound to a tenant + agent class.\n *\n * Ordered by descending priority then name so callers that don't need the\n * full resolver still get a deterministic, priority-first ordering.\n */\n async byTenantAndClass(\n tenantId: string,\n agentClass: string,\n ): Promise<AgentPersona[]> {\n return this.listForClass(tenantId, agentClass);\n }\n\n /**\n * List the enabled personas for a tenant + agent class, filtered to those\n * applicable to a context.\n *\n * `enabled` is filtered in the query; the context predicate (tenant-wide vs\n * type-scoped vs exact) is applied in memory since it is an OR over several\n * columns. A persona is applicable when it is a tenant-wide default (no\n * `contextType`) or its context matches the requested one. Ordered by\n * descending priority then name.\n *\n * @param context - Optional `{ contextType, contextId }` to filter by.\n */\n async findActive(\n tenantId: string,\n agentClass: string,\n context: { contextType?: string | null; contextId?: string | null } = {},\n ): Promise<AgentPersona[]> {\n const personas = await this.listForClass(tenantId, agentClass, {\n enabled: true,\n });\n return personas.filter((persona) =>\n personaAppliesToContext(persona, context),\n );\n }\n}\n\n/**\n * Whether a persona applies to a requested context.\n *\n * - No `contextType` on the persona → tenant-wide default, applies to all.\n * - `contextType` set, `contextId` null → type-scoped, applies when the\n * requested `contextType` matches.\n * - Both set → exact, applies when both match.\n */\nexport function personaAppliesToContext(\n persona: Pick<AgentPersona, 'contextType' | 'contextId'>,\n context: { contextType?: string | null; contextId?: string | null },\n): boolean {\n if (!persona.contextType) {\n return true;\n }\n if (persona.contextType !== (context.contextType ?? null)) {\n return false;\n }\n if (persona.contextId == null) {\n return true;\n }\n return persona.contextId === (context.contextId ?? null);\n}\n\n/**\n * Context-specificity rank used for resolution ordering.\n *\n * - `2` exact `(contextType, contextId)` match\n * - `1` type-scoped match (`contextType` matches, persona `contextId` null)\n * - `0` tenant-wide default (persona has no `contextType`)\n */\nexport function personaContextRank(\n persona: Pick<AgentPersona, 'contextType' | 'contextId'>,\n): number {\n if (!persona.contextType) {\n return 0;\n }\n return persona.contextId == null ? 1 : 2;\n}\n\nfunction sortByPriorityThenName(personas: AgentPersona[]): AgentPersona[] {\n return [...personas].sort((a, b) => {\n if (b.priority !== a.priority) {\n return b.priority - a.priority;\n }\n return (a.name ?? '').localeCompare(b.name ?? '');\n });\n}\n\nexport default AgentPersona;\n","/**\n * DirectiveProposal — a pending, human-reviewable edit to a persona's\n * instructions (#1889).\n *\n * The autonomous {@link ReflectionRunner} consolidates recent episodes and\n * {@link Feedback} into candidate rewrites of a persona's instructions and\n * records each as a pending `DirectiveProposal` (rationale + evidence). A\n * proposal is inert data: it changes nothing until a human who holds the\n * `personas.activate-directive` permission approves it through the review\n * queue, at which point the persona-scoped `prompt_override` is written.\n *\n * The reflection principal deliberately lacks that permission, so it can only\n * *propose* — the permission split is the gate. See {@link DirectiveApprovalService}.\n *\n * @module\n */\n\nimport {\n field,\n foreignKey,\n SmrtCollection,\n SmrtObject,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\n\n/**\n * Lifecycle status of a proposal:\n *\n * - `pending` — awaiting review; surfaced in the queue.\n * - `approved` — a reviewer activated it; the override was written.\n * - `rejected` — a reviewer declined it; recorded as a signal and never\n * re-surfaced (the runner dedups against it by fingerprint).\n * - `superseded` — a newer proposal replaced it before review.\n */\nexport type DirectiveProposalStatus =\n | 'pending'\n | 'approved'\n | 'rejected'\n | 'superseded';\n\n/**\n * Structured evidence backing a proposal — the ids of the learning episodes and\n * feedback signals the reflection consolidated. Pure references so the proposal\n * stays auditable without duplicating payloads.\n */\nexport interface DirectiveEvidence {\n /** `_smrt_contexts` row ids of the episodes considered. */\n episodeIds?: string[];\n /** {@link Feedback} row ids considered. */\n feedbackIds?: string[];\n /** Free-form supporting notes (e.g. counts, aggregate metrics). */\n notes?: string[];\n [key: string]: unknown;\n}\n\n/**\n * A stable content fingerprint for `(personaId, promptKey, proposedInstructions)`.\n *\n * Used to dedup proposals so an already-reviewed rewrite — in particular a\n * rejected one — is never re-surfaced. Pure FNV-1a so it needs no crypto import\n * and stays identical across Node and browser bundles.\n */\nexport function computeDirectiveFingerprint(\n personaId: string,\n promptKey: string,\n proposedInstructions: string,\n): string {\n const input = `${personaId} ${promptKey} ${proposedInstructions}`;\n let hash = 0x811c9dc5;\n for (let i = 0; i < input.length; i++) {\n hash ^= input.charCodeAt(i);\n // FNV prime multiply, kept in 32-bit unsigned space.\n hash = Math.imul(hash, 0x01000193) >>> 0;\n }\n return hash.toString(16).padStart(8, '0');\n}\n\nfunction parseEvidence(raw: unknown): DirectiveEvidence {\n if (typeof raw !== 'string' || raw.length === 0) {\n return raw && typeof raw === 'object' ? (raw as DirectiveEvidence) : {};\n }\n try {\n const parsed = JSON.parse(raw);\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed)\n ? (parsed as DirectiveEvidence)\n : {};\n } catch {\n return {};\n }\n}\n\n/**\n * A pending, human-reviewable proposed edit to a persona's instructions.\n */\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'directive_proposals',\n // Read-only generated surface: activation/rejection go through the\n // permission-gated DirectiveApprovalService, not generated CRUD writes.\n api: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n})\nexport class DirectiveProposal extends SmrtObject {\n /** Owning tenant (required — proposals always target a tenant's persona). */\n @tenantId()\n tenantId: string = '';\n\n /** The persona whose instructions this proposal would rewrite. */\n @foreignKey('AgentPersona', { required: true })\n personaId: string = '';\n\n /** Canonical agent class the persona configures (denormalised for queries). */\n @field({ type: 'text' })\n agentClass: string = '';\n\n /**\n * The registered prompt key whose template the persona's instructions map to.\n * Activation writes/updates the tenant-scoped override for this key.\n */\n @field({ type: 'text' })\n promptKey: string = '';\n\n /** The proposed replacement instructions (the new prompt template). */\n @field({ type: 'text' })\n proposedInstructions: string = '';\n\n /** Snapshot of the instructions at proposal time (for a review diff). */\n @field({ type: 'text' })\n currentInstructions: string = '';\n\n /** Model-authored explanation for the proposed change. */\n @field({ type: 'text' })\n rationale: string = '';\n\n /** Structured evidence, stored as a JSON string (see {@link getEvidence}). */\n @field({ type: 'text' })\n evidence: string = '{}';\n\n /** Lifecycle status. */\n @field({ type: 'text' })\n status: DirectiveProposalStatus = 'pending';\n\n /**\n * Content fingerprint for dedup / not-re-surfacing. Set from\n * {@link computeDirectiveFingerprint} at creation time.\n */\n @field({ type: 'text' })\n fingerprint: string = '';\n\n /** Aggregate confidence in the proposal, in `[0, 1]`. */\n confidence: number = 0.0;\n\n /** Id of the principal (autonomous reflection actor) that proposed it. */\n @field({ type: 'text' })\n proposedBy: string = '';\n\n /** The reviewer (user id) that approved/rejected it, once reviewed. */\n @field({ type: 'text', nullable: true })\n reviewedBy: string | null = null;\n\n /** When the proposal was reviewed. */\n @field({ type: 'datetime', nullable: true })\n reviewedAt: Date | null = null;\n\n /** Reviewer note attached on approve/reject. */\n @field({ type: 'text', nullable: true })\n reviewNote: string | null = null;\n\n /** The `prompt_override` id written on activation (`null` until approved). */\n @field({ type: 'text', nullable: true })\n activatedOverrideId: string | null = null;\n\n /** Parse {@link evidence}, tolerating malformed JSON. */\n getEvidence(): DirectiveEvidence {\n return parseEvidence(this.evidence);\n }\n\n /** Replace {@link evidence}. */\n setEvidence(value: DirectiveEvidence): void {\n this.evidence = JSON.stringify(value ?? {});\n }\n\n /** Whether the proposal is still awaiting review. */\n isPending(): boolean {\n return this.status === 'pending';\n }\n}\n\n/**\n * Collection for {@link DirectiveProposal} rows — the review queue.\n */\nexport class DirectiveProposalCollection extends SmrtCollection<DirectiveProposal> {\n static readonly _itemClass = DirectiveProposal;\n\n /**\n * The review queue: pending proposals, oldest first. Optionally scoped to a\n * persona.\n */\n async pending(\n options: { personaId?: string; limit?: number } = {},\n ): Promise<DirectiveProposal[]> {\n const where: Record<string, unknown> = { status: 'pending' };\n if (options.personaId) {\n where.personaId = options.personaId;\n }\n return this.list({\n where,\n orderBy: 'created_at ASC',\n limit: options.limit,\n });\n }\n\n /**\n * Existing proposals for a persona carrying a given fingerprint, in any\n * status — used to avoid re-surfacing an already-seen (e.g. rejected) rewrite.\n */\n async findByFingerprint(\n personaId: string,\n fingerprint: string,\n ): Promise<DirectiveProposal[]> {\n return this.list({ where: { personaId, fingerprint } });\n }\n}\n\nexport default DirectiveProposal;\n","/**\n * Feedback — reinforcement signals for a persona's learning loop (#1889).\n *\n * A `Feedback` row captures one reinforcement signal against a persona and the\n * `LearningMemory` episode it pertains to. Two families of signal are modelled:\n *\n * - **Human signals** — `accept` / `reject` / `correction` / `rating`: an\n * operator's judgement on an agent's behaviour.\n * - **Autonomous signals** — `outcome` / `metric`: a machine-observed result\n * (a boolean success or a numeric measurement) captured without a human.\n *\n * Every signal carries a **correlation-id** back to the thing it judges — the\n * AI call, dispatch, or job whose result prompted the feedback — so a signal\n * can always be traced to its cause. Signals feed the confidence-scored\n * reinforcement in {@link LearningMemory} (#1886) via {@link toLearningOutcome}:\n * this is the automatic, confidence-only half of the loop. The gated half —\n * rewriting a persona's instructions — lives in the directive-proposal flow.\n *\n * @module\n */\n\nimport {\n field,\n foreignKey,\n type LearningOutcome,\n SmrtCollection,\n SmrtObject,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\n\n/**\n * The kind of reinforcement signal a {@link Feedback} row carries.\n *\n * `accept` / `reject` / `correction` / `rating` are human judgements;\n * `outcome` / `metric` are machine-observed autonomous signals.\n */\nexport type FeedbackSignalType =\n | 'accept'\n | 'reject'\n | 'correction'\n | 'rating'\n | 'outcome'\n | 'metric';\n\n/** Whether a signal originated from a person or an autonomous observation. */\nexport type FeedbackSource = 'human' | 'autonomous';\n\n/** The human-authored signal types. */\nexport const HUMAN_SIGNAL_TYPES: readonly FeedbackSignalType[] = [\n 'accept',\n 'reject',\n 'correction',\n 'rating',\n];\n\n/**\n * Return the natural source for a signal type: the human judgement types are\n * `'human'`; `outcome` / `metric` are `'autonomous'`.\n */\nexport function feedbackSourceFor(signal: FeedbackSignalType): FeedbackSource {\n return HUMAN_SIGNAL_TYPES.includes(signal) ? 'human' : 'autonomous';\n}\n\n/** Options for {@link Feedback.toLearningOutcome}. */\nexport interface FeedbackOutcomeOptions {\n /**\n * The neutral point of a `rating` scale. A rating strictly above the neutral\n * reinforces as a success; at or below it decays as a failure. Default `0`\n * (any positive rating is a success), matching {@link LearningOutcome}'s\n * metric convention. Pass e.g. `3` for a 1–5 star scale.\n */\n ratingNeutral?: number;\n}\n\nfunction parseJsonObject(raw: unknown): Record<string, unknown> {\n if (typeof raw !== 'string' || raw.length === 0) {\n return raw && typeof raw === 'object'\n ? (raw as Record<string, unknown>)\n : {};\n }\n try {\n const parsed = JSON.parse(raw);\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : {};\n } catch {\n return {};\n }\n}\n\n/**\n * A single reinforcement signal against a persona and a learning episode.\n */\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'agent_feedback',\n api: { include: ['list', 'get', 'create'] },\n cli: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n})\nexport class Feedback extends SmrtObject {\n /** Owning tenant (optional — autonomous signals may be tenant-less). */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /** The persona this signal judges. */\n @foreignKey('AgentPersona', { required: true })\n personaId: string = '';\n\n /** Canonical agent class the persona configures (denormalised for queries). */\n @field({ type: 'text' })\n agentClass: string = '';\n\n /**\n * Memory scope the signal reinforces — the partition key routing it to the\n * right {@link LearningMemory} so different personas reinforce independently.\n */\n @field({ type: 'text' })\n memoryScope: string = '';\n\n /** Learning episode scope this signal pertains to (`LearningEpisode.scope`). */\n @field({ type: 'text' })\n scope: string = '';\n\n /** Learning episode key this signal pertains to (`LearningEpisode.key`). */\n @field({ type: 'text' })\n key: string = '';\n\n /** The kind of signal (see {@link FeedbackSignalType}). */\n @field({ type: 'text' })\n signalType: FeedbackSignalType = 'outcome';\n\n /** Whether the signal is human or autonomous. */\n @field({ type: 'text' })\n source: FeedbackSource = 'autonomous';\n\n /**\n * Correlation-id back to the thing this signal judges — the AI call,\n * dispatch, or job id. Required so a signal is always traceable to its cause.\n */\n @field({ type: 'text', required: true })\n correlationId: string = '';\n\n /**\n * What kind of thing {@link correlationId} names (e.g. `'ai_call'`,\n * `'dispatch'`, `'job'`). `null` when the namespace is implicit.\n */\n @field({ type: 'text', nullable: true })\n correlationType: string | null = null;\n\n /** Numeric rating for a `rating` signal (scale is caller-defined). */\n @field({ type: 'decimal', nullable: true })\n rating: number | null = null;\n\n /** Observed measurement for a `metric` signal. */\n @field({ type: 'decimal', nullable: true })\n metric: number | null = null;\n\n /** Observed boolean result for an `outcome` signal. */\n @field({ type: 'boolean', nullable: true })\n success: boolean | null = null;\n\n /**\n * Corrected instructions/value for a `correction` signal — the human-supplied\n * replacement that should supersede the strategy that was judged wrong.\n */\n @field({ type: 'text', nullable: true })\n correction: string | null = null;\n\n /** Freeform note attached to the signal. */\n @field({ type: 'text', nullable: true })\n comment: string | null = null;\n\n /** The user id that authored a human signal (`null` for autonomous). */\n @field({ type: 'text', nullable: true })\n actorId: string | null = null;\n\n /** Arbitrary structured metadata, stored as a JSON string. */\n @field({ type: 'text' })\n metadata: string = '{}';\n\n /**\n * When this signal was applied to memory as reinforcement. `null` until a\n * reflection pass consumes it. Gates exactly-once reinforcement so a scheduled\n * runner never re-applies the same signal (which would amplify a single\n * accept/reject into many outcomes).\n */\n @field({ type: 'datetime', nullable: true })\n reinforcedAt: Date | null = null;\n\n /** Whether this is a human-authored signal. */\n isHuman(): boolean {\n return this.source === 'human';\n }\n\n /** Parse {@link metadata}, tolerating malformed JSON. */\n getMetadata(): Record<string, unknown> {\n return parseJsonObject(this.metadata);\n }\n\n /** Replace {@link metadata}. */\n setMetadata(value: Record<string, unknown>): void {\n this.metadata = JSON.stringify(value ?? {});\n }\n\n /** Shallow-merge into {@link metadata}. */\n updateMetadata(patch: Record<string, unknown>): void {\n this.setMetadata({ ...this.getMetadata(), ...patch });\n }\n\n /**\n * The strategy value a `correction` signal should persist into memory, so a\n * regenerated (corrected) strategy supersedes the one that was judged wrong.\n * `undefined` for non-correction signals (reinforce confidence only).\n */\n getCorrectionValue(): string | undefined {\n return this.signalType === 'correction' && this.correction != null\n ? this.correction\n : undefined;\n }\n\n /**\n * Map this signal onto a {@link LearningOutcome} for reinforcement, or `null`\n * when the signal carries no reinforcement value:\n *\n * - `accept` → success; `reject` / `correction` → failure.\n * - `outcome` → the recorded boolean `success`.\n * - `metric` → the recorded `metric` (positive → success).\n * - `rating` → `{ metric: rating - ratingNeutral }`.\n */\n toLearningOutcome(\n options: FeedbackOutcomeOptions = {},\n ): LearningOutcome | null {\n switch (this.signalType) {\n case 'accept':\n return { success: true };\n case 'reject':\n case 'correction':\n return { success: false, error: this.comment ?? undefined };\n case 'outcome':\n return this.success == null ? null : { success: this.success };\n case 'metric':\n return this.metric == null ? null : { metric: this.metric };\n case 'rating': {\n if (this.rating == null) {\n return null;\n }\n return { metric: this.rating - (options.ratingNeutral ?? 0) };\n }\n default:\n return null;\n }\n }\n}\n\n/**\n * Collection for {@link Feedback} rows.\n */\nexport class FeedbackCollection extends SmrtCollection<Feedback> {\n static readonly _itemClass = Feedback;\n\n /** All signals for a persona, newest first. */\n async forPersona(\n personaId: string,\n options: { limit?: number } = {},\n ): Promise<Feedback[]> {\n return this.list({\n where: { personaId },\n orderBy: 'created_at DESC',\n limit: options.limit,\n });\n }\n\n /** All signals filed under a memory scope, newest first. */\n async forScope(\n memoryScope: string,\n options: { limit?: number } = {},\n ): Promise<Feedback[]> {\n return this.list({\n where: { memoryScope },\n orderBy: 'created_at DESC',\n limit: options.limit,\n });\n }\n\n /** Every signal correlated to a given AI call / dispatch / job id. */\n async byCorrelation(correlationId: string): Promise<Feedback[]> {\n return this.list({\n where: { correlationId },\n orderBy: 'created_at DESC',\n });\n }\n}\n\nexport default Feedback;\n","/**\n * Persona ↔ prompt-override binding (#1889).\n *\n * A persona's `instructions` are applied to the running agent through a\n * **tenant/persona-scoped `prompt_override`**, not by mutating the agent's code\n * default. Each persona owns a dedicated, per-persona prompt key registered at\n * runtime with a neutral empty base template; the persona's actual instructions\n * live entirely in the override layer. Because the key is unique per persona,\n * two personas of the same tenant and agent class resolve to different\n * instructions without colliding on the `(key, context)` override identity.\n *\n * Activating a directive (see {@link DirectiveApprovalService}) is exactly the\n * act of writing/updating this override — and it flows through\n * `PromptOverride.save()`, so `validatePromptOverride` still forbids overriding\n * a non-editable prompt field.\n *\n * @module\n */\n\nimport {\n definePrompt,\n type PromptDefinition,\n type PromptEditableConfig,\n type PromptOverride,\n PromptOverrideCollection,\n PromptRegistry,\n resolvePrompt,\n} from '@happyvertical/smrt-prompts';\nimport type { DatabaseInterface } from '@happyvertical/sql';\n\n/** The minimal persona shape these helpers need. */\nexport interface PersonaLike {\n id?: string | null;\n tenantId?: string | null;\n instructions?: string;\n}\n\n/**\n * The registered prompt key a persona's instructions map to.\n *\n * @throws if the persona has no id (an unsaved persona has no stable key).\n */\nexport function personaInstructionsPromptKey(persona: PersonaLike): string {\n const id = persona.id;\n if (!id) {\n throw new Error(\n 'personaInstructionsPromptKey requires a persisted persona (missing id)',\n );\n }\n return `persona.${id}.instructions`;\n}\n\n/** Default editability for a persona instructions prompt: template-only. */\nconst DEFAULT_PERSONA_EDITABLE: PromptEditableConfig = {\n template: true,\n profile: false,\n model: false,\n params: false,\n};\n\n/**\n * Idempotently register the per-persona instructions prompt.\n *\n * The base template is always the empty string and the editability is fixed, so\n * repeated calls register an identical definition (the registry is idempotent\n * for matching definitions). The persona's real instructions are supplied by\n * the override layer, never by the base template — that keeps re-registration\n * stable even as instructions change.\n *\n * Pass `editable` to model a prompt whose template is locked; activation of a\n * proposal against such a key is then rejected by `validatePromptOverride`.\n */\nexport function ensurePersonaInstructionsPrompt(\n persona: PersonaLike,\n options: { editable?: Partial<PromptEditableConfig> } = {},\n): PromptDefinition {\n const key = personaInstructionsPromptKey(persona);\n const existing = PromptRegistry.get(key);\n // Fast path only when the caller does not assert a specific editability. When\n // `editable` IS given, always go through definePrompt so a conflicting\n // re-registration (e.g. trying to lock `template: false` over an already\n // editable key) is rejected loudly rather than silently ignored.\n if (existing && options.editable === undefined) {\n return existing;\n }\n return definePrompt({\n key,\n template: '',\n editable: { ...DEFAULT_PERSONA_EDITABLE, ...(options.editable ?? {}) },\n });\n}\n\n/**\n * Upsert a scoped `prompt_override` template for a registered prompt key.\n *\n * Loads the existing app/tenant override (by `tenantId`), updates its template,\n * or creates a new one. Always flows through `PromptOverride.save()`, so\n * `validatePromptOverride` still forbids overriding a non-editable template.\n *\n * The prompt key must already be registered (via\n * {@link ensurePersonaInstructionsPrompt} or `definePrompt`); this helper does\n * not register it, so it never silently relaxes a locked prompt's editability.\n *\n * @returns The persisted override.\n */\nexport async function upsertPromptTemplateOverride(options: {\n db: DatabaseInterface;\n key: string;\n tenantId: string | null;\n template: string;\n}): Promise<PromptOverride> {\n const { db, key, tenantId, template } = options;\n const overrides = await PromptOverrideCollection.create({ db });\n const existing =\n tenantId != null\n ? await overrides.getTenantOverride(key, tenantId)\n : await overrides.getAppOverride(key);\n\n if (existing) {\n existing.template = template;\n await existing.save();\n return existing;\n }\n\n return overrides.create({ key, tenantId, template });\n}\n\n/**\n * Write (or update) the tenant-scoped `prompt_override` that carries a persona's\n * instructions.\n *\n * Ensures the per-persona prompt key is registered, then upserts the override\n * template to `instructions ?? persona.instructions`. Flows through\n * `PromptOverride.save()`, so a non-editable template throws.\n *\n * @returns The persisted override.\n */\nexport async function applyPersonaInstructions(options: {\n persona: PersonaLike;\n db: DatabaseInterface;\n instructions?: string;\n editable?: Partial<PromptEditableConfig>;\n}): Promise<PromptOverride> {\n const { persona, db } = options;\n ensurePersonaInstructionsPrompt(persona, { editable: options.editable });\n return upsertPromptTemplateOverride({\n db,\n key: personaInstructionsPromptKey(persona),\n tenantId: persona.tenantId ?? null,\n template: options.instructions ?? persona.instructions ?? '',\n });\n}\n\n/**\n * Resolve a persona's effective instructions through the prompt system —\n * layering code default → config → app override → tenant (persona) override.\n *\n * @returns The rendered instructions text (empty string when nothing overrides\n * the neutral base template).\n */\nexport async function resolvePersonaInstructions(options: {\n persona: PersonaLike;\n db: DatabaseInterface;\n variables?: Record<string, unknown>;\n}): Promise<string> {\n const { persona, db } = options;\n ensurePersonaInstructionsPrompt(persona);\n const key = personaInstructionsPromptKey(persona);\n const resolved = await resolvePrompt(key, {\n db,\n tenantId: persona.tenantId ?? null,\n variables: options.variables,\n });\n return resolved.text;\n}\n","/**\n * DirectiveApprovalService — the human-in-the-loop gate (#1889).\n *\n * The review queue's write side. A reviewer who holds the\n * `personas.activate-directive` permission can **approve** (optionally editing\n * the text), or **reject**, a pending {@link DirectiveProposal}:\n *\n * - **approve** activates the persona-scoped `prompt_override` (through\n * `PromptOverride.save()`, so a non-editable prompt template is refused by\n * `validatePromptOverride`) and records an `accept` signal.\n * - **reject** records a `reject` signal and closes the proposal so the\n * reflection runner never re-surfaces the same rewrite (it dedups on\n * fingerprint against non-pending proposals too).\n *\n * The gate is purely the permission check: an actor lacking the slug — the\n * autonomous reflection principal included — is denied before anything is\n * written. Confidence-only reinforcement is unaffected; it never passes here.\n *\n * @module\n */\n\nimport type { PromptOverride } from '@happyvertical/smrt-prompts';\nimport type { DatabaseInterface } from '@happyvertical/sql';\nimport { AgentPersonaCollection } from './agent-persona.js';\nimport {\n ACTIVATE_DIRECTIVE_PERMISSION,\n type DirectivePrincipal,\n} from './directive-principal.js';\nimport {\n DirectiveProposal,\n DirectiveProposalCollection,\n} from './directive-proposal.js';\nimport { type Feedback, FeedbackCollection } from './feedback.js';\nimport { upsertPromptTemplateOverride } from './persona-prompt.js';\n\n/** Raised when a principal without the activation permission attempts to review. */\nexport class DirectiveActivationDeniedError extends Error {\n constructor(\n message = `Principal lacks the '${ACTIVATE_DIRECTIVE_PERMISSION}' permission required to review persona directives`,\n ) {\n super(message);\n this.name = 'DirectiveActivationDeniedError';\n }\n}\n\n/** Raised when a review is attempted on a proposal that is not pending. */\nexport class DirectiveNotPendingError extends Error {\n constructor(status: string) {\n super(`Directive proposal is not pending (status: ${status})`);\n this.name = 'DirectiveNotPendingError';\n }\n}\n\n/** Options for {@link DirectiveApprovalService}. */\nexport interface DirectiveApprovalServiceOptions {\n db: DatabaseInterface;\n proposals?: DirectiveProposalCollection;\n feedback?: FeedbackCollection;\n personas?: AgentPersonaCollection;\n}\n\n/** Result of approving a proposal. */\nexport interface DirectiveApprovalResult {\n proposal: DirectiveProposal;\n /** The activated persona-scoped override. */\n override: PromptOverride;\n /** The recorded `accept` signal. */\n signal: Feedback;\n}\n\n/** Result of rejecting a proposal. */\nexport interface DirectiveRejectionResult {\n proposal: DirectiveProposal;\n /** The recorded `reject` signal. */\n signal: Feedback;\n}\n\n/** A proposal reference: the row, or its id. */\nexport type ProposalRef = DirectiveProposal | string;\n\n/**\n * The permission-gated review surface for persona directives.\n */\nexport class DirectiveApprovalService {\n private readonly db: DatabaseInterface;\n private proposals?: DirectiveProposalCollection;\n private feedback?: FeedbackCollection;\n private personas?: AgentPersonaCollection;\n\n constructor(options: DirectiveApprovalServiceOptions) {\n this.db = options.db;\n this.proposals = options.proposals;\n this.feedback = options.feedback;\n this.personas = options.personas;\n }\n\n /**\n * Assert a principal is authorised to review directives. The single gate:\n * everything privileged in this service calls it first.\n *\n * @throws {DirectiveActivationDeniedError} when the principal lacks the slug.\n */\n assertCanActivate(principal: DirectivePrincipal): void {\n if (!principal.can(ACTIVATE_DIRECTIVE_PERMISSION)) {\n throw new DirectiveActivationDeniedError();\n }\n }\n\n /**\n * Assert a principal may review a specific proposal: its resolved tenant, when\n * bound, must match the proposal's tenant. Permissions are resolved per\n * tenant, so holding the slug in one tenant must not authorise activating\n * another tenant's directive.\n *\n * @throws {DirectiveActivationDeniedError} on a cross-tenant attempt.\n */\n private assertTenantMatch(\n principal: DirectivePrincipal,\n proposal: DirectiveProposal,\n ): void {\n if (\n principal.tenantId !== undefined &&\n principal.tenantId !== proposal.tenantId\n ) {\n throw new DirectiveActivationDeniedError(\n `Principal (tenant '${principal.tenantId}') cannot review a directive for tenant '${proposal.tenantId}'`,\n );\n }\n }\n\n /**\n * Approve a pending proposal: activate the persona-scoped override and record\n * an `accept` signal. Pass `editedInstructions` to activate a revised text\n * (the proposal keeps the model's original as its audit record; the override\n * holds what was activated).\n *\n * @throws {DirectiveActivationDeniedError} when the principal lacks the slug.\n * @throws {DirectiveNotPendingError} when the proposal is already reviewed.\n */\n async approve(\n ref: ProposalRef,\n principal: DirectivePrincipal,\n options: { note?: string; editedInstructions?: string } = {},\n ): Promise<DirectiveApprovalResult> {\n this.assertCanActivate(principal);\n const proposal = await this.loadPending(ref);\n this.assertTenantMatch(principal, proposal);\n\n const template =\n options.editedInstructions ?? proposal.proposedInstructions;\n\n // Activation is exactly writing the persona-scoped override. This flows\n // through PromptOverride.save() → validatePromptOverride, so a non-editable\n // template is refused here (the error propagates to the reviewer).\n const override = await upsertPromptTemplateOverride({\n db: this.db,\n key: proposal.promptKey,\n tenantId: proposal.tenantId,\n template,\n });\n\n // Keep the persona's own `instructions` field in sync with the activated\n // text, so the field-based `PersonaResolver.resolve()` path reflects the\n // approved directive too — not only the prompt-override path. Best effort:\n // the override is the authoritative application; a missing persona (e.g.\n // deleted) does not fail the activation.\n await this.syncPersonaInstructions(proposal.personaId, template);\n\n proposal.status = 'approved';\n proposal.reviewedBy = principal.id ?? null;\n proposal.reviewedAt = new Date();\n proposal.reviewNote = options.note ?? null;\n proposal.activatedOverrideId = override.id ?? null;\n await proposal.save();\n\n const signal = await this.recordSignal(proposal, 'accept', principal, {\n note: options.note,\n edited: options.editedInstructions !== undefined,\n });\n\n return { proposal, override, signal };\n }\n\n /**\n * Reject a pending proposal: record a `reject` signal and close it so it is\n * never re-surfaced.\n *\n * @throws {DirectiveActivationDeniedError} when the principal lacks the slug.\n * @throws {DirectiveNotPendingError} when the proposal is already reviewed.\n */\n async reject(\n ref: ProposalRef,\n principal: DirectivePrincipal,\n options: { note?: string } = {},\n ): Promise<DirectiveRejectionResult> {\n this.assertCanActivate(principal);\n const proposal = await this.loadPending(ref);\n this.assertTenantMatch(principal, proposal);\n\n proposal.status = 'rejected';\n proposal.reviewedBy = principal.id ?? null;\n proposal.reviewedAt = new Date();\n proposal.reviewNote = options.note ?? null;\n await proposal.save();\n\n const signal = await this.recordSignal(proposal, 'reject', principal, {\n note: options.note,\n });\n\n return { proposal, signal };\n }\n\n private async loadPending(ref: ProposalRef): Promise<DirectiveProposal> {\n const proposal =\n ref instanceof DirectiveProposal ? ref : await this.getProposal(ref);\n if (!proposal) {\n throw new Error(`Directive proposal not found: ${String(ref)}`);\n }\n if (proposal.status !== 'pending') {\n throw new DirectiveNotPendingError(proposal.status);\n }\n return proposal;\n }\n\n private async getProposal(id: string): Promise<DirectiveProposal | null> {\n const proposals = await this.proposalsCollection();\n return proposals.get({ id });\n }\n\n private async recordSignal(\n proposal: DirectiveProposal,\n signalType: 'accept' | 'reject',\n principal: DirectivePrincipal,\n options: { note?: string; edited?: boolean } = {},\n ): Promise<Feedback> {\n const feedback = await this.feedbackCollection();\n return feedback.create({\n tenantId: proposal.tenantId,\n personaId: proposal.personaId,\n agentClass: proposal.agentClass,\n memoryScope: '',\n scope: 'persona/directive',\n key: proposal.id ?? '',\n signalType,\n source: 'human',\n // The correlation-id ties the signal back to the reviewed proposal.\n correlationId: proposal.id ?? '',\n correlationType: 'directive_proposal',\n actorId: principal.id ?? null,\n comment: options.note ?? null,\n metadata: JSON.stringify({ edited: options.edited ?? false }),\n });\n }\n\n private async syncPersonaInstructions(\n personaId: string,\n instructions: string,\n ): Promise<void> {\n const personas = await this.personasCollection();\n const persona = await personas.get({ id: personaId });\n if (!persona) {\n return;\n }\n persona.instructions = instructions;\n await persona.save();\n }\n\n private async personasCollection(): Promise<AgentPersonaCollection> {\n if (!this.personas) {\n this.personas = await AgentPersonaCollection.create({ db: this.db });\n }\n return this.personas;\n }\n\n private async proposalsCollection(): Promise<DirectiveProposalCollection> {\n if (!this.proposals) {\n this.proposals = await DirectiveProposalCollection.create({\n db: this.db,\n });\n }\n return this.proposals;\n }\n\n private async feedbackCollection(): Promise<FeedbackCollection> {\n if (!this.feedback) {\n this.feedback = await FeedbackCollection.create({ db: this.db });\n }\n return this.feedback;\n }\n}\n","/**\n * Persona-scoped learning memory routing (#1889).\n *\n * A persona's `memoryScope` routes {@link LearningMemory} so different personas\n * of the same agent class learn independently. The scope becomes the memory\n * partition (`owner_id`), so two personas never share confidence-scored\n * strategies even when they run the identical agent class over the same tenant.\n *\n * The other direction of the loop — turning a {@link Feedback} signal into a\n * confidence adjustment — is {@link reinforceFromFeedback}: the automatic,\n * confidence-only reinforcement that stays ungated (only instruction rewrites\n * are gated).\n *\n * @module\n */\n\nimport {\n LearningMemory,\n type LearningMemoryConfig,\n type LearningMemoryRecord,\n type LearningSemanticSearch,\n} from '@happyvertical/smrt-core';\nimport type { DatabaseInterface } from '@happyvertical/sql';\nimport type { Feedback, FeedbackOutcomeOptions } from './feedback.js';\n\n/** The minimal persona shape the memory router needs. */\nexport interface PersonaMemoryLike {\n id?: string | null;\n memoryScope?: string;\n agentClass?: string;\n tenantId?: string | null;\n}\n\n/**\n * The effective memory partition key for a persona: its explicit `memoryScope`,\n * or a stable `persona:<id>` fallback when none is set.\n *\n * @throws if neither a `memoryScope` nor an id is available.\n */\nexport function personaMemoryScope(persona: PersonaMemoryLike): string {\n const explicit = persona.memoryScope?.trim();\n if (explicit) {\n return explicit;\n }\n if (persona.id) {\n return `persona:${persona.id}`;\n }\n throw new Error(\n 'personaMemoryScope requires a persona with a memoryScope or an id',\n );\n}\n\n/**\n * Build a {@link LearningMemory} partitioned to a persona's memory scope.\n *\n * The persona's `memoryScope` is used as the memory `owner_id`, so recall and\n * capture are isolated per persona. `owner_class` defaults to the persona's\n * agent class (falling back to `'AgentPersona'`).\n */\nexport function personaLearningMemory(options: {\n db: DatabaseInterface;\n persona: PersonaMemoryLike;\n ownerClass?: string;\n tenantId?: string | null;\n semanticSearch?: LearningSemanticSearch;\n config?: Partial<LearningMemoryConfig>;\n}): LearningMemory {\n const ownerClass =\n options.ownerClass ??\n (options.persona.agentClass?.trim() || 'AgentPersona');\n return new LearningMemory({\n db: options.db,\n ownerClass,\n ownerId: personaMemoryScope(options.persona),\n tenantId: options.tenantId ?? options.persona.tenantId ?? null,\n semanticSearch: options.semanticSearch,\n config: options.config,\n });\n}\n\n/**\n * Apply a single {@link Feedback} signal to a persona's memory as\n * confidence-only reinforcement.\n *\n * Maps the signal onto a `LearningOutcome` and captures it against the episode\n * the signal names (`feedback.scope` / `feedback.key`). A `correction` signal\n * additionally supersedes the stored strategy with the corrected value.\n *\n * @returns The updated/seeded memory record, or `null` when the signal carries\n * no reinforcement value (or there was nothing to reinforce).\n */\nexport async function reinforceFromFeedback(\n memory: LearningMemory,\n feedback: Feedback,\n options: FeedbackOutcomeOptions = {},\n): Promise<LearningMemoryRecord | null> {\n const outcome = feedback.toLearningOutcome(options);\n if (!outcome) {\n return null;\n }\n const value = feedback.getCorrectionValue();\n return memory.capture(\n {\n scope: feedback.scope,\n key: feedback.key,\n ...(value !== undefined ? { value } : {}),\n },\n outcome,\n );\n}\n","/**\n * Persona-as-durable-instance helpers (#1890).\n *\n * Treats an {@link AgentPersona} as a **durable instance** of an agent class:\n * N configured instances per tenant, each independently scheduled, memory-scoped,\n * and permission-scoped. This module wires that instance concept to the\n * `@happyvertical/smrt-agents` runtime:\n *\n * - **Identity** — {@link personaInstanceKey} / {@link agentOptionsForPersona}\n * map a persona to the `AgentOptions.instanceKey` the framework folds into a\n * per-instance dispatch subscriber, memory scope, and interest scope. The\n * `default` persona reuses the **singleton** identity (a `null` key), which is\n * what makes the singleton→multi upgrade non-destructive.\n * - **Scheduling** — {@link schedulePersonaInstance} binds an `AgentSchedule` to\n * a persona instance, routing the instance key through `agentConfig` so it\n * reaches the constructed agent as `AgentOptions.instanceKey`.\n * - **Admin** — {@link buildPersonaInstanceAdmin} renders the agent class's\n * `uiSlots`/`adminRoutes` once per instance, with {@link addPersonaInstance} /\n * {@link removePersonaInstance} affordances.\n * - **Upgrade** — {@link upgradeSingletonToDefaultPersona} maps an existing\n * singleton to a single `default` persona without touching its data.\n *\n * Multi-instance is a per-package opt-in on the agent class\n * (`static multiInstance = true`); these helpers manage the persona rows that\n * back it. A singleton (non-opted) agent needs none of this and is unchanged.\n */\n\nimport {\n type AgentAdminRoute,\n type AgentManifestInfo,\n type AgentSchedule,\n type AgentScheduleCollection,\n type AgentUISlots,\n instanceScopedSubscriber,\n} from '@happyvertical/smrt-agents';\nimport {\n type AgentPersona,\n type AgentPersonaCollection,\n canonicalAgentClass,\n} from './agent-persona.js';\n\n/**\n * The reserved persona name for the singleton/default instance.\n *\n * Matches the `PersonaResolver` default-fallback name so the concept is\n * consistent across the package. A persona with this name is the tenant's\n * singleton identity: it maps to a `null` instance key (see\n * {@link personaInstanceKey}), reusing the class-keyed dispatch subscriber and\n * un-suffixed memory scope an un-upgraded agent already uses.\n */\nexport const DEFAULT_PERSONA_NAME = 'default';\n\n/**\n * The durable per-instance key for a persona, or `null` for the singleton.\n *\n * - The `default` persona → `null`: it *is* the singleton identity, so an agent\n * run as it keeps the class-keyed dispatch subscriber and un-suffixed memory\n * scope. This is why upgrading a singleton to a default persona changes no\n * runtime identity (non-destructive).\n * - Any other persona → its `id`: a distinct, stable instance key the framework\n * folds into a per-instance subscriber/memory/interest scope.\n *\n * @throws Error if a non-default persona has no `id` (it must be saved first —\n * an unsaved non-default persona would masquerade as the singleton).\n */\nexport function personaInstanceKey(\n persona: Pick<AgentPersona, 'name' | 'id'>,\n): string | null {\n if (persona.name === DEFAULT_PERSONA_NAME) {\n return null;\n }\n if (!persona.id) {\n throw new Error(\n 'personaInstanceKey: a non-default persona must be saved (have an id) ' +\n 'before it can act as a durable instance',\n );\n }\n return persona.id;\n}\n\n/**\n * Whether a persona is the singleton/default instance.\n */\nexport function isDefaultPersona(persona: Pick<AgentPersona, 'name'>): boolean {\n return persona.name === DEFAULT_PERSONA_NAME;\n}\n\n/**\n * The subset of `AgentOptions` a runtime spreads to construct an agent as this\n * persona instance. Kept structural (no agents runtime import needed by the\n * caller) — spread into `new AgentClass({ ...agentOptionsForPersona(p), db })`.\n */\nexport interface PersonaAgentOptions {\n /** Per-instance key — `null` for the default (singleton) persona. */\n instanceKey: string | null;\n /** The tenant the persona belongs to. */\n tenantId: string;\n}\n\n/**\n * Project a persona into the agent construction options that give the agent its\n * per-instance identity.\n */\nexport function agentOptionsForPersona(\n persona: AgentPersona,\n): PersonaAgentOptions {\n return {\n instanceKey: personaInstanceKey(persona),\n tenantId: persona.tenantId,\n };\n}\n\n/**\n * Options for {@link schedulePersonaInstance}.\n */\nexport interface SchedulePersonaInstanceOptions {\n /** Cron expression (5-field). */\n cron: string;\n /** Timezone label (default `'UTC'`). */\n timezone?: string;\n /** Agent method to invoke (default `'run'`). */\n method?: string;\n /** Config passed to the agent on each run. */\n agentConfig?: Record<string, unknown>;\n /** Arguments passed to the method. */\n methodArgs?: Record<string, unknown>;\n /** Whether the schedule starts enabled (default `true`). */\n enabled?: boolean;\n}\n\n/**\n * Create an `AgentSchedule` bound to a persona **instance**.\n *\n * The schedule's `agentType` is the persona's agent class. The persona instance\n * key ({@link personaInstanceKey}) must reach the constructed agent as\n * `AgentOptions.instanceKey`, so it is carried in `agentConfig` — which the\n * scheduler (`smrt-jobs`) spreads into the agent constructor options — and\n * `agentId` is left **null**.\n *\n * This is deliberate: the scheduler copies `AgentSchedule.agentId` to\n * `SmrtJob.objectId`, and the `TaskRunner` `loadFromId()`s a non-null\n * `objectId` against the agent's STI table. A persona id lives in\n * `agent_personas`, not that table, so putting it in `agentId` would fail to\n * load (or load the wrong row). Leaving `agentId` null makes the runner\n * construct a fresh instance and pick up `instanceKey` from `agentConfig`. The\n * default persona (null key) carries no key → runs the singleton.\n *\n * @param schedules - The `AgentScheduleCollection` to create into.\n * @param persona - The persona instance to schedule (must be saved).\n * @param options - Cron and run settings.\n */\nexport async function schedulePersonaInstance(\n schedules: AgentScheduleCollection,\n persona: AgentPersona,\n options: SchedulePersonaInstanceOptions,\n): Promise<AgentSchedule> {\n const instanceKey = personaInstanceKey(persona);\n const agentConfig: Record<string, unknown> = {\n ...(options.agentConfig ?? {}),\n };\n if (instanceKey) {\n agentConfig.instanceKey = instanceKey;\n }\n const schedule = await schedules.create({\n tenantId: persona.tenantId,\n agentType: persona.agentClass,\n agentId: null,\n cron: options.cron,\n timezone: options.timezone ?? 'UTC',\n method: options.method ?? 'run',\n agentConfig,\n methodArgs: options.methodArgs ?? {},\n enabled: options.enabled ?? true,\n });\n await schedule.save();\n return schedule;\n}\n\n/**\n * One instance's row in the instance-aware admin surface.\n *\n * Carries the agent class's admin surface (`slots` / `adminRoutes`) rendered for\n * THIS instance, plus the resolved per-instance dispatch subscriber so the admin\n * can show how the instance is routed.\n */\nexport interface PersonaInstanceView {\n /** The persona id backing this instance. */\n personaId: string;\n /** Persona (instance) name. */\n name: string;\n /** Per-instance key — `null` for the default (singleton). */\n instanceKey: string | null;\n /** Whether this is the default (singleton) instance. */\n isDefault: boolean;\n /** Whether the instance is enabled. */\n enabled: boolean;\n /** Resolution priority. */\n priority: number;\n /** Context scoping (if any). */\n contextType: string | null;\n contextId: string | null;\n /** The principal the instance runs as. */\n runAsUserId: string;\n /** Optional acting bot identity. */\n actsAsProfileId: string | null;\n /** The per-instance dispatch subscriber identity. */\n dispatchSubscriber: string;\n /** The agent class's UI slots, rendered for this instance. */\n slots: AgentUISlots;\n /** The agent class's admin routes, rendered for this instance. */\n adminRoutes: AgentAdminRoute[];\n}\n\n/**\n * The instance-aware admin surface for one `(tenant, agentClass)` pair.\n */\nexport interface PersonaInstanceAdminView {\n /** Canonical agent class the surface is for. */\n agentClass: string;\n /** Tenant the surface is for. */\n tenantId: string;\n /** One entry per configured instance (persona), priority-ordered. */\n instances: PersonaInstanceView[];\n /** Whether new instances may be added (always true for the persona model). */\n canAddInstance: boolean;\n}\n\n/**\n * Options for {@link buildPersonaInstanceAdmin}.\n */\nexport interface BuildPersonaInstanceAdminOptions {\n /** Tenant to render the surface for. */\n tenantId: string;\n /** Agent class (canonicalized internally). */\n agentClass: string;\n /**\n * The agent class's manifest surface. Its `uiSlots` / `adminRoutes` are\n * rendered once per instance. Optional — omit to render instances with empty\n * panels (e.g. a class that declares none).\n */\n manifest?: Pick<AgentManifestInfo, 'uiSlots' | 'adminRoutes'>;\n}\n\n/**\n * Build the instance-aware admin surface: one panel set per configured instance.\n *\n * Lists the tenant's persona instances for the class and renders the class's\n * `uiSlots`/`adminRoutes` for each, so an admin sees N instances (not one class\n * panel) with add/remove affordances. The default (singleton) instance appears\n * with `instanceKey: null` and the class-keyed subscriber.\n *\n * @param personas - Persona collection to read instances from.\n * @param options - Tenant, class, and the class manifest to render per instance.\n */\nexport async function buildPersonaInstanceAdmin(\n personas: AgentPersonaCollection,\n options: BuildPersonaInstanceAdminOptions,\n): Promise<PersonaInstanceAdminView> {\n const canonical = canonicalAgentClass(options.agentClass);\n const slots = options.manifest?.uiSlots ?? {};\n const adminRoutes = options.manifest?.adminRoutes ?? [];\n\n const rows = await personas.byTenantAndClass(options.tenantId, canonical);\n\n const instances: PersonaInstanceView[] = rows.map((persona) => {\n const instanceKey = personaInstanceKey(persona);\n return {\n personaId: persona.id as string,\n name: persona.name,\n instanceKey,\n isDefault: isDefaultPersona(persona),\n enabled: persona.enabled,\n priority: persona.priority,\n contextType: persona.contextType,\n contextId: persona.contextId,\n runAsUserId: persona.runAsUserId,\n actsAsProfileId: persona.actsAsProfileId,\n dispatchSubscriber: instanceScopedSubscriber(canonical, instanceKey),\n slots,\n adminRoutes,\n };\n });\n\n return {\n agentClass: canonical,\n tenantId: options.tenantId,\n instances,\n canAddInstance: true,\n };\n}\n\n/**\n * Options for {@link addPersonaInstance}.\n */\nexport interface AddPersonaInstanceOptions {\n tenantId: string;\n agentClass: string;\n /** Instance name (unique per `(tenant, agentClass)`). */\n name: string;\n /** The principal the instance runs as (required by `AgentPersona`). */\n runAsUserId: string;\n instructions?: string;\n allowedTools?: string[];\n contextType?: string | null;\n contextId?: string | null;\n priority?: number;\n memoryScope?: string;\n actsAsProfileId?: string | null;\n enabled?: boolean;\n}\n\n/**\n * Add a new instance (persona) — the \"add\" admin affordance.\n *\n * Creates and saves an `AgentPersona`, canonicalizing the agent class so it\n * lines up with `TenantAgent`. The `(tenant_id, agent_class, name)` unique\n * constraint rejects a duplicate name.\n */\nexport async function addPersonaInstance(\n personas: AgentPersonaCollection,\n options: AddPersonaInstanceOptions,\n): Promise<AgentPersona> {\n const persona = await personas.create({\n tenantId: options.tenantId,\n agentClass: canonicalAgentClass(options.agentClass),\n name: options.name,\n instructions: options.instructions ?? '',\n contextType: options.contextType ?? null,\n contextId: options.contextId ?? null,\n priority: options.priority ?? 0,\n enabled: options.enabled ?? true,\n runAsUserId: options.runAsUserId,\n actsAsProfileId: options.actsAsProfileId ?? null,\n memoryScope: options.memoryScope ?? '',\n });\n if (options.allowedTools) {\n persona.setAllowedTools(options.allowedTools);\n }\n await persona.save();\n return persona;\n}\n\n/**\n * Remove an instance (persona) by id — the \"remove\" admin affordance.\n *\n * Deletes only the named instance; other instances of the class are untouched.\n * A no-op (returns `false`) when the persona does not exist.\n *\n * @returns `true` if a persona was removed, `false` if none matched the id.\n */\nexport async function removePersonaInstance(\n personas: AgentPersonaCollection,\n personaId: string,\n): Promise<boolean> {\n const persona = await personas.get({ id: personaId });\n if (!persona) {\n return false;\n }\n await persona.delete();\n return true;\n}\n\n/**\n * Options for {@link upgradeSingletonToDefaultPersona}.\n */\nexport interface UpgradeSingletonOptions {\n tenantId: string;\n agentClass: string;\n /** The principal the default persona runs as (required by `AgentPersona`). */\n runAsUserId: string;\n /** Instructions to seed the default persona with (from existing config). */\n instructions?: string;\n /** Tools to seed (from existing config). */\n allowedTools?: string[];\n /**\n * Memory scope for the default persona. Leave empty (default) to let the\n * resolver derive it — for the default (null-keyed) instance the derived\n * scope equals the singleton's existing `agent/<type>` scope, so existing\n * learned memory is preserved untouched.\n */\n memoryScope?: string;\n actsAsProfileId?: string | null;\n}\n\n/**\n * The result of a singleton→multi upgrade.\n */\nexport interface UpgradeSingletonResult {\n /** The default persona representing the existing singleton instance. */\n persona: AgentPersona;\n /** `true` if it was created now, `false` if a default persona already existed. */\n created: boolean;\n /**\n * The instance key for the default persona — always `null`, i.e. it maps to\n * the existing singleton runtime identity (same dispatch subscriber + memory\n * scope), which is what makes the upgrade non-destructive.\n */\n instanceKey: null;\n}\n\n/**\n * Non-destructively upgrade a singleton agent to the multi-instance model by\n * mapping the existing instance to a single `default` persona.\n *\n * The default persona is null-keyed, so it *reuses the singleton's exact runtime\n * identity* — the class-keyed dispatch subscriber and the un-suffixed\n * `agent/<type>` memory scope. Nothing about the running agent, its config, its\n * dispatch subscriptions, or its learned memory changes; a persona row is simply\n * added so further instances can now be created alongside it.\n *\n * Idempotent: if a `default` persona already exists for the pair it is returned\n * with `created: false` and nothing is duplicated.\n *\n * @param personas - Persona collection to read/create into.\n * @param options - Tenant, class, and the principal + config to seed.\n */\nexport async function upgradeSingletonToDefaultPersona(\n personas: AgentPersonaCollection,\n options: UpgradeSingletonOptions,\n): Promise<UpgradeSingletonResult> {\n const canonical = canonicalAgentClass(options.agentClass);\n\n const existing = await personas.byTenantAndClass(options.tenantId, canonical);\n const existingDefault = existing.find(isDefaultPersona);\n if (existingDefault) {\n return { persona: existingDefault, created: false, instanceKey: null };\n }\n\n const persona = await addPersonaInstance(personas, {\n tenantId: options.tenantId,\n agentClass: canonical,\n name: DEFAULT_PERSONA_NAME,\n runAsUserId: options.runAsUserId,\n instructions: options.instructions,\n allowedTools: options.allowedTools,\n memoryScope: options.memoryScope,\n actsAsProfileId: options.actsAsProfileId,\n priority: 0,\n enabled: true,\n });\n\n return { persona, created: true, instanceKey: null };\n}\n","/**\n * PersonaResolver - resolves the active {@link AgentPersona} for a\n * `(tenant, agentClass, context)` request.\n *\n * Layering, bottom to top (each layer overrides the previous):\n *\n * 1. **Manifest defaults** — the agent's built-in instructions / tools /\n * memory scope (supplied by the caller as {@link ManifestPersonaDefaults}).\n * 2. **TenantAgent** — the tenant/class availability gate and capability\n * ceiling (supplied as a {@link PersonaAvailabilityGate}; build one from a\n * `ResolvedAgentAvailability` via {@link availabilityFromResolvedAgent}).\n * `TenantAgent` decides *whether* the agent runs and *caps* its tools;\n * it never sets instructions.\n * 3. **AgentPersona** — the tenant's own persona for the context: overrides\n * instructions, sets tools (within the ceiling), run-as principal, acting\n * identity, and memory scope.\n *\n * Tenant-hierarchy inheritance mirrors `TenantAgentCollection.resolveForTenant`:\n * the resolver walks from the requesting tenant up its ancestors (nearest\n * first). The nearest tenant level that has any applicable persona wins the\n * resolution (a closer level shadows a farther one); within that level the most\n * context-specific, highest-priority persona is selected. When no level has an\n * applicable persona a defined default is returned.\n *\n * The hierarchy walk reads personas across tenants, so `resolve()` is meant to\n * run in a system/admin path where cross-tenant reads are permitted (i.e. not\n * inside a strict per-tenant interceptor context) — the same expectation\n * `TenantAgentCollection.resolveForTenant` carries.\n */\n\nimport type { ResolvedAgentAvailability } from '@happyvertical/smrt-agents';\nimport {\n type AgentPersona,\n type AgentPersonaCollection,\n canonicalAgentClass,\n personaAppliesToContext,\n personaContextRank,\n} from './agent-persona.js';\n\n/**\n * The context a persona is being resolved for.\n */\nexport interface PersonaContext {\n /** Context dimension type (e.g. `'site'`). */\n contextType?: string | null;\n /** Context dimension id within `contextType`. */\n contextId?: string | null;\n}\n\n/**\n * Bottom-layer defaults for an agent class, typically derived from its build\n * manifest.\n */\nexport interface ManifestPersonaDefaults {\n /** Default system instructions when no persona overrides them. */\n instructions?: string;\n /** Default tool identifiers, capped by the availability ceiling. */\n allowedTools?: string[];\n /** Default memory scope. */\n memoryScope?: string;\n}\n\n/**\n * Middle-layer availability + capability ceiling, projected from a\n * `TenantAgent` resolution.\n */\nexport interface PersonaAvailabilityGate {\n /** Resolved `TenantAgent` status. `'disabled'` marks the persona unavailable. */\n status: 'active' | 'disabled';\n /**\n * Tool identifiers the tenant is permitted to grant. When set, resolved\n * `allowedTools` are intersected with this ceiling. `undefined` means no\n * ceiling (tools pass through unchanged).\n */\n toolCeiling?: string[];\n /** Tenant the binding was resolved from (provenance only). */\n sourceTenantId?: string;\n}\n\n/**\n * Options for {@link PersonaResolver.resolve}.\n */\nexport interface ResolvePersonaOptions {\n /**\n * Return ancestor tenant ids for a tenant, nearest parent first through to\n * the root — mirrors `TenantAgentCollection.resolveForTenant`. Omit for a\n * single-tenant resolution with no inheritance.\n */\n getAncestorIds?: (tenantId: string) => Promise<string[]>;\n /** Bottom-layer manifest defaults for the agent class. */\n manifestDefaults?: ManifestPersonaDefaults;\n /**\n * Middle-layer `TenantAgent` availability + ceiling. Omit to skip gating\n * (the result is always `available: true` with no tool ceiling).\n */\n availability?: PersonaAvailabilityGate | null;\n}\n\n/**\n * A fully resolved persona: the layered, ready-to-use configuration plus\n * provenance describing how it was resolved.\n */\nexport interface ResolvedPersona {\n /** Canonical qualified agent type the resolution was for. */\n agentClass: string;\n /** Tenant the resolution was requested for. */\n tenantId: string;\n /** Id of the selected persona, or `undefined` for the default fallback. */\n personaId?: string;\n /** Selected persona name, or `'default'` for the fallback. */\n name: string;\n /** Layered instructions (persona → manifest default). */\n instructions: string;\n /** Layered tool ids (persona/manifest tools, capped by the ceiling). */\n allowedTools: string[];\n /** Run-as user principal, if the selected persona sets one. */\n runAsUserId?: string;\n /** Acting `Bot` profile id, if the selected persona sets one. */\n actsAsProfileId?: string | null;\n /** Resolved memory scope (persona → manifest default → derived default). */\n memoryScope: string;\n /** Selected persona priority (`0` for the default fallback). */\n priority: number;\n /** Context type the resolution was requested for. */\n contextType?: string | null;\n /** Context id the resolution was requested for. */\n contextId?: string | null;\n /** Whether a persona matched (`'persona'`) or the default was used (`'default'`). */\n source: 'persona' | 'default';\n /** For a matched persona, whether it was the tenant's own or inherited. */\n personaSource?: 'explicit' | 'inherited';\n /** Tenant the matched persona came from (own tenant or an ancestor). */\n sourceTenantId?: string;\n /** Whether the `TenantAgent` gate reports the agent as available. */\n available: boolean;\n}\n\n/**\n * Project a `TenantAgent` resolution into a {@link PersonaAvailabilityGate}.\n *\n * This is the concrete bridge between the `@happyvertical/smrt-agents`\n * availability layer and the persona layer. Pass `toolPermissionPrefix` to\n * derive a tool ceiling from granted permission ids (permissions whose id\n * starts with the prefix become the ceiling, with the prefix stripped); omit it\n * to leave the ceiling open.\n *\n * @param resolved - A `ResolvedAgentAvailability` (or `null`/`undefined`).\n * @param options.toolPermissionPrefix - Permission-id prefix that marks\n * tool grants (e.g. `'tool:'`).\n * @returns A gate, or `null` when `resolved` is nullish.\n */\nexport function availabilityFromResolvedAgent(\n resolved: ResolvedAgentAvailability | null | undefined,\n options: { toolPermissionPrefix?: string } = {},\n): PersonaAvailabilityGate | null {\n if (!resolved) {\n return null;\n }\n\n const { toolPermissionPrefix } = options;\n let toolCeiling: string[] | undefined;\n if (toolPermissionPrefix) {\n toolCeiling = Object.entries(resolved.permissions ?? {})\n .filter(([id, granted]) => granted && id.startsWith(toolPermissionPrefix))\n .map(([id]) => id.slice(toolPermissionPrefix.length))\n // Sort for a stable, order-independent ceiling regardless of how the\n // permissions map was produced.\n .sort();\n }\n\n return {\n status: resolved.status,\n toolCeiling,\n sourceTenantId: resolved.sourceTenantId,\n };\n}\n\n/**\n * Resolves the active persona for a `(tenant, agentClass, context)` request.\n */\nexport class PersonaResolver {\n constructor(private readonly personas: AgentPersonaCollection) {}\n\n /**\n * Resolve the active persona.\n *\n * @param tenantId - Requesting tenant.\n * @param agentClass - Agent class (canonicalized internally).\n * @param context - Context dimension being resolved for.\n * @param options - Hierarchy walk, manifest defaults, and availability gate.\n * @returns The layered {@link ResolvedPersona} — either a matched persona or\n * the defined default fallback.\n */\n async resolve(\n tenantId: string,\n agentClass: string,\n context: PersonaContext = {},\n options: ResolvePersonaOptions = {},\n ): Promise<ResolvedPersona> {\n const canonical = canonicalAgentClass(agentClass);\n const { getAncestorIds, manifestDefaults, availability } = options;\n\n const ancestorIds = getAncestorIds ? await getAncestorIds(tenantId) : [];\n const levels = [tenantId, ...ancestorIds];\n\n for (let level = 0; level < levels.length; level++) {\n const levelTenantId = levels[level];\n const candidates = await this.personas.findActive(\n levelTenantId,\n canonical,\n context,\n );\n\n if (candidates.length === 0) {\n continue;\n }\n\n const winner = pickWinner(candidates);\n return this.layerPersona(winner, {\n canonical,\n tenantId,\n context,\n manifestDefaults,\n availability,\n personaSource: level === 0 ? 'explicit' : 'inherited',\n sourceTenantId: levelTenantId,\n });\n }\n\n return this.defaultResolution({\n canonical,\n tenantId,\n context,\n manifestDefaults,\n availability,\n });\n }\n\n private layerPersona(\n persona: AgentPersona,\n ctx: LayerContext & {\n personaSource: 'explicit' | 'inherited';\n sourceTenantId: string;\n },\n ): ResolvedPersona {\n const { manifestDefaults, availability } = ctx;\n const personaTools = persona.getAllowedTools();\n const baseTools =\n personaTools.length > 0\n ? personaTools\n : (manifestDefaults?.allowedTools ?? []);\n\n return {\n agentClass: ctx.canonical,\n tenantId: ctx.tenantId,\n personaId: persona.id ?? undefined,\n name: persona.name,\n instructions:\n persona.instructions || manifestDefaults?.instructions || '',\n allowedTools: applyCeiling(baseTools, availability),\n runAsUserId: persona.runAsUserId || undefined,\n actsAsProfileId: persona.actsAsProfileId ?? null,\n memoryScope: resolveMemoryScope(persona.memoryScope, ctx),\n priority: persona.priority,\n contextType: ctx.context.contextType ?? null,\n contextId: ctx.context.contextId ?? null,\n source: 'persona',\n personaSource: ctx.personaSource,\n sourceTenantId: ctx.sourceTenantId,\n available: isAvailable(availability),\n };\n }\n\n private defaultResolution(ctx: LayerContext): ResolvedPersona {\n const { manifestDefaults, availability } = ctx;\n return {\n agentClass: ctx.canonical,\n tenantId: ctx.tenantId,\n name: 'default',\n instructions: manifestDefaults?.instructions ?? '',\n allowedTools: applyCeiling(\n manifestDefaults?.allowedTools ?? [],\n availability,\n ),\n actsAsProfileId: null,\n memoryScope: resolveMemoryScope('', ctx),\n priority: 0,\n contextType: ctx.context.contextType ?? null,\n contextId: ctx.context.contextId ?? null,\n source: 'default',\n available: isAvailable(availability),\n };\n }\n}\n\ninterface LayerContext {\n canonical: string;\n tenantId: string;\n context: PersonaContext;\n manifestDefaults?: ManifestPersonaDefaults;\n availability?: PersonaAvailabilityGate | null;\n}\n\n/**\n * Pick the winning persona from candidates already known to apply to the\n * requested context and be enabled.\n *\n * Order: most context-specific first, then highest priority, then name for a\n * stable deterministic tie-break.\n */\nfunction pickWinner(candidates: AgentPersona[]): AgentPersona {\n return [...candidates].sort((a, b) => {\n const rankDelta = personaContextRank(b) - personaContextRank(a);\n if (rankDelta !== 0) {\n return rankDelta;\n }\n if (b.priority !== a.priority) {\n return b.priority - a.priority;\n }\n return (a.name ?? '').localeCompare(b.name ?? '');\n })[0];\n}\n\nfunction applyCeiling(\n tools: string[],\n availability?: PersonaAvailabilityGate | null,\n): string[] {\n if (!availability?.toolCeiling) {\n return [...tools];\n }\n const ceiling = new Set(availability.toolCeiling);\n return tools.filter((tool) => ceiling.has(tool));\n}\n\nfunction isAvailable(availability?: PersonaAvailabilityGate | null): boolean {\n return availability ? availability.status === 'active' : true;\n}\n\nfunction resolveMemoryScope(explicit: string, ctx: LayerContext): string {\n if (explicit) {\n return explicit;\n }\n if (ctx.manifestDefaults?.memoryScope) {\n return ctx.manifestDefaults.memoryScope;\n }\n const contextSuffix = ctx.context.contextType\n ? `:${ctx.context.contextType}${ctx.context.contextId ? `:${ctx.context.contextId}` : ''}`\n : '';\n return `${ctx.canonical}:${ctx.tenantId}${contextSuffix}`;\n}\n\n// Re-export the context applicability helper for consumers building their own\n// persona selection UIs without duplicating the semantics.\nexport { personaAppliesToContext };\n","/**\n * ReflectionRunner — the scheduled consolidation step of the learning loop (#1889).\n *\n * Runs under the **autonomous reflection principal**, which deliberately lacks\n * the `personas.activate-directive` permission. For a persona it:\n *\n * 1. Applies recent {@link Feedback} to the persona's {@link LearningMemory}\n * as automatic, confidence-only reinforcement (ungated).\n * 2. Consolidates the resulting episodes + feedback and asks an injected\n * reflector (the AI boundary, mocked in tests) for a candidate rewrite of\n * the persona's instructions.\n * 3. Records that rewrite as a **pending** {@link DirectiveProposal} with\n * rationale + evidence — deduped by fingerprint so an already-seen (e.g.\n * rejected) rewrite is never re-surfaced.\n *\n * It cannot activate anything: writing the persona override is gated by the\n * permission its principal does not hold. That split is the whole gate.\n *\n * The runner is transport-agnostic; schedule it through an `AgentSchedule` /\n * background job by calling {@link run} on a cadence.\n *\n * @module\n */\n\nimport type {\n LearningMemory,\n LearningMemoryRecord,\n} from '@happyvertical/smrt-core';\nimport type { DatabaseInterface } from '@happyvertical/sql';\nimport type { DirectivePrincipal } from './directive-principal.js';\nimport {\n computeDirectiveFingerprint,\n type DirectiveProposal,\n DirectiveProposalCollection,\n} from './directive-proposal.js';\nimport { type Feedback, FeedbackCollection } from './feedback.js';\nimport { reinforceFromFeedback } from './persona-memory.js';\nimport {\n ensurePersonaInstructionsPrompt,\n personaInstructionsPromptKey,\n resolvePersonaInstructions,\n} from './persona-prompt.js';\n\n/** The (normalised) persona shape handed to the reflector. */\nexport interface ReflectionPersona {\n id: string;\n tenantId: string;\n agentClass?: string;\n name?: string;\n instructions?: string;\n memoryScope?: string;\n}\n\n/**\n * The persona a run consolidates over — accepts a persisted `AgentPersona`\n * directly (its `id` / `tenantId` are validated at run time).\n */\nexport interface ReflectionPersonaInput {\n id?: string | null;\n tenantId?: string | null;\n agentClass?: string;\n name?: string;\n instructions?: string;\n memoryScope?: string;\n}\n\n/** The consolidated input handed to the reflector (the AI boundary). */\nexport interface ReflectionInput {\n persona: ReflectionPersona;\n /** The persona's current effective instructions (resolved via prompts). */\n currentInstructions: string;\n /** Recent episodes for the persona's memory scope. */\n episodes: LearningMemoryRecord[];\n /** Recent feedback signals for the persona. */\n feedback: Feedback[];\n}\n\n/** A candidate rewrite returned by the reflector. */\nexport interface DirectiveDraft {\n /** Proposed replacement instructions. */\n instructions: string;\n /** Model-authored explanation. */\n rationale: string;\n /** Optional aggregate confidence in `[0, 1]`. */\n confidence?: number;\n}\n\n/**\n * The reflection boundary: consolidate episodes + feedback into a proposed\n * instruction rewrite, or `null` to propose nothing. Injected so the AI call is\n * the only thing mocked in tests.\n */\nexport type DirectiveReflector = (\n input: ReflectionInput,\n) => Promise<DirectiveDraft | null> | DirectiveDraft | null;\n\n/** Options for {@link ReflectionRunner}. */\nexport interface ReflectionRunnerOptions {\n db: DatabaseInterface;\n /** The autonomous principal — must NOT hold `personas.activate-directive`. */\n principal: DirectivePrincipal;\n /** The reflection boundary (AI call), injected. */\n reflect: DirectiveReflector;\n proposals?: DirectiveProposalCollection;\n feedback?: FeedbackCollection;\n /** Clock, injectable for deterministic lookback in tests. */\n now?: () => Date;\n}\n\n/** Options for a single {@link ReflectionRunner.run} pass over one persona. */\nexport interface ReflectionRunOptions {\n persona: ReflectionPersonaInput;\n /** The persona-scoped learning memory (see `personaLearningMemory`). */\n memory: LearningMemory;\n /** Episode scope to recall for evidence. Omit to skip episode gathering. */\n episodeScope?: string;\n /** Only consider feedback newer than this many ms ago. */\n lookbackMs?: number;\n /** Cap on feedback rows considered. Default 50. */\n feedbackLimit?: number;\n /** Neutral point for `rating` signals during reinforcement. Default 0. */\n ratingNeutral?: number;\n /** Override the target prompt key (default the persona instructions key). */\n promptKey?: string;\n}\n\n/** Result of a {@link ReflectionRunner.run} pass. */\nexport interface ReflectionRunResult {\n /** Newly created pending proposals (0 or 1). */\n proposals: DirectiveProposal[];\n /** Number of feedback signals that adjusted memory reinforcement. */\n reinforced: number;\n /** Number of candidate rewrites suppressed (deduped / no-op). */\n skipped: number;\n}\n\nfunction normalizePersona(input: ReflectionPersonaInput): ReflectionPersona {\n if (!input.id) {\n throw new Error(\n 'ReflectionRunner.run requires a persisted persona (missing id)',\n );\n }\n if (!input.tenantId) {\n throw new Error(\n 'ReflectionRunner.run requires a tenant-scoped persona (missing tenantId)',\n );\n }\n return {\n id: input.id,\n tenantId: input.tenantId,\n agentClass: input.agentClass,\n name: input.name,\n instructions: input.instructions,\n memoryScope: input.memoryScope,\n };\n}\n\nfunction meanConfidence(episodes: LearningMemoryRecord[]): number {\n if (episodes.length === 0) {\n return 0.5;\n }\n const sum = episodes.reduce((acc, e) => acc + e.confidence, 0);\n return sum / episodes.length;\n}\n\n/**\n * Consolidates feedback + episodes into pending directive proposals under a\n * principal that cannot activate them.\n */\nexport class ReflectionRunner {\n private readonly db: DatabaseInterface;\n private readonly reflect: DirectiveReflector;\n private readonly now: () => Date;\n private readonly _principal: DirectivePrincipal;\n private proposalsCol?: DirectiveProposalCollection;\n private feedbackCol?: FeedbackCollection;\n\n constructor(options: ReflectionRunnerOptions) {\n this.db = options.db;\n this._principal = options.principal;\n this.reflect = options.reflect;\n this.now = options.now ?? (() => new Date());\n this.proposalsCol = options.proposals;\n this.feedbackCol = options.feedback;\n }\n\n /**\n * The autonomous principal this runner acts as. Exposed so callers can prove\n * it cannot activate a proposal (it lacks `personas.activate-directive`).\n */\n get principal(): DirectivePrincipal {\n return this._principal;\n }\n\n /**\n * Run one reflection pass for a persona.\n */\n async run(options: ReflectionRunOptions): Promise<ReflectionRunResult> {\n const { memory } = options;\n const persona = normalizePersona(options.persona);\n const feedbackCol = await this.feedbackCollection();\n\n // 1. Recent feedback for the persona (optionally windowed).\n const feedbackLimit = options.feedbackLimit ?? 50;\n let feedback = await feedbackCol.forPersona(persona.id, {\n limit: feedbackLimit,\n });\n if (options.lookbackMs != null) {\n const cutoff = this.now().getTime() - options.lookbackMs;\n feedback = feedback.filter((f) => {\n const created = f.created_at ? new Date(f.created_at).getTime() : 0;\n return created >= cutoff;\n });\n }\n\n // 2. Automatic, confidence-only reinforcement — applied EXACTLY ONCE per\n // signal. A signal already consumed (`reinforcedAt` set) is skipped, so a\n // scheduled runner never re-applies it and amplifies one accept/reject\n // into many outcomes. Directive review signals (accept/reject of a\n // proposal) judge a proposal, not an episode, so they are marked consumed\n // without reinforcing.\n let reinforced = 0;\n for (const signal of feedback) {\n if (signal.reinforcedAt) {\n continue;\n }\n if (signal.correlationType !== 'directive_proposal') {\n const record = await reinforceFromFeedback(memory, signal, {\n ratingNeutral: options.ratingNeutral,\n });\n if (record) {\n reinforced += 1;\n }\n }\n signal.reinforcedAt = this.now();\n await signal.save();\n }\n\n // 3. Gather episodes as evidence (all confidences, including decayed ones).\n const episodes = options.episodeScope\n ? await memory.recall(options.episodeScope, {\n minConfidence: 0,\n includeAncestors: true,\n })\n : [];\n\n // 4. Resolve the persona's current instructions, then ask the reflector.\n ensurePersonaInstructionsPrompt(persona);\n const currentInstructions = await resolvePersonaInstructions({\n persona,\n db: this.db,\n });\n\n const draft = await this.reflect({\n persona,\n currentInstructions,\n episodes,\n feedback,\n });\n\n if (!draft || draft.instructions.trim() === currentInstructions.trim()) {\n // Nothing to propose, or a no-op rewrite.\n return { proposals: [], reinforced, skipped: draft ? 1 : 0 };\n }\n\n // 5. Dedup by fingerprint so an already-seen (e.g. rejected) rewrite is\n // never re-surfaced.\n const promptKey =\n options.promptKey ?? personaInstructionsPromptKey(persona);\n const fingerprint = computeDirectiveFingerprint(\n persona.id,\n promptKey,\n draft.instructions,\n );\n const proposals = await this.proposalsCollection();\n const existing = await proposals.findByFingerprint(persona.id, fingerprint);\n if (existing.length > 0) {\n return { proposals: [], reinforced, skipped: 1 };\n }\n\n // 6. Record the pending proposal (rationale + evidence). It is inert until a\n // permissioned human activates it.\n const proposal = await proposals.create({\n tenantId: persona.tenantId,\n personaId: persona.id,\n agentClass: persona.agentClass ?? '',\n promptKey,\n proposedInstructions: draft.instructions,\n currentInstructions,\n rationale: draft.rationale,\n status: 'pending',\n fingerprint,\n confidence: draft.confidence ?? meanConfidence(episodes),\n proposedBy: this._principal.id ?? 'reflection',\n evidence: JSON.stringify({\n episodeIds: episodes.map((e) => e.id),\n feedbackIds: feedback\n .map((f) => f.id)\n .filter((id): id is string => Boolean(id)),\n }),\n });\n\n return { proposals: [proposal], reinforced, skipped: 0 };\n }\n\n private async proposalsCollection(): Promise<DirectiveProposalCollection> {\n if (!this.proposalsCol) {\n this.proposalsCol = await DirectiveProposalCollection.create({\n db: this.db,\n });\n }\n return this.proposalsCol;\n }\n\n private async feedbackCollection(): Promise<FeedbackCollection> {\n if (!this.feedbackCol) {\n this.feedbackCol = await FeedbackCollection.create({ db: this.db });\n }\n return this.feedbackCol;\n }\n}\n","/**\n * @happyvertical/smrt-personas\n *\n * Tenant-owned, context-scoped agent personas and their resolution. Layers over\n * `@happyvertical/smrt-agents`' `TenantAgent` availability/ceiling gate to\n * decide how an agent should behave for a given tenant and context.\n *\n * Also home to the persona **learning & adaptation loop** (#1889): feedback\n * signals feed confidence-scored reinforcement, a scheduled reflection runner\n * consolidates episodes + feedback into pending directive proposals, and a\n * permission-gated approval service (the `personas.activate-directive` split)\n * activates an approved rewrite as a tenant/persona-scoped prompt override.\n *\n * @packageDocumentation\n */\n\n// Self-register this package's manifest before any @smrt() decorator fires\n// downstream. Must come first so the side effect runs ahead of the class\n// module loads below. See __smrt-register__.ts for issue #1132 context.\nimport './__smrt-register__.js';\n\nimport { ensurePersonaPermissionsRegistered } from './directive-principal.js';\n\nexport {\n AgentPersona,\n AgentPersonaCollection,\n canonicalAgentClass,\n personaAppliesToContext,\n personaContextRank,\n} from './agent-persona.js';\nexport {\n DirectiveActivationDeniedError,\n type DirectiveApprovalResult,\n DirectiveApprovalService,\n type DirectiveApprovalServiceOptions,\n DirectiveNotPendingError,\n type DirectiveRejectionResult,\n type ProposalRef,\n} from './directive-approval.js';\nexport {\n ACTIVATE_DIRECTIVE_PERMISSION,\n DIRECTIVE_ACTIVATION_PERMISSION_DEF,\n type DirectivePrincipal,\n ensurePersonaPermissionsRegistered,\n principalFromPermissions,\n registerPersonaPermissions,\n resolveDirectivePrincipal,\n} from './directive-principal.js';\nexport {\n computeDirectiveFingerprint,\n type DirectiveEvidence,\n DirectiveProposal,\n DirectiveProposalCollection,\n type DirectiveProposalStatus,\n} from './directive-proposal.js';\nexport {\n Feedback,\n FeedbackCollection,\n type FeedbackOutcomeOptions,\n type FeedbackSignalType,\n type FeedbackSource,\n feedbackSourceFor,\n HUMAN_SIGNAL_TYPES,\n} from './feedback.js';\nexport {\n type PersonaMemoryLike,\n personaLearningMemory,\n personaMemoryScope,\n reinforceFromFeedback,\n} from './persona-memory.js';\nexport {\n applyPersonaInstructions,\n ensurePersonaInstructionsPrompt,\n type PersonaLike,\n personaInstructionsPromptKey,\n resolvePersonaInstructions,\n upsertPromptTemplateOverride,\n} from './persona-prompt.js';\nexport {\n type AddPersonaInstanceOptions,\n addPersonaInstance,\n agentOptionsForPersona,\n type BuildPersonaInstanceAdminOptions,\n buildPersonaInstanceAdmin,\n DEFAULT_PERSONA_NAME,\n isDefaultPersona,\n type PersonaAgentOptions,\n type PersonaInstanceAdminView,\n type PersonaInstanceView,\n personaInstanceKey,\n removePersonaInstance,\n type SchedulePersonaInstanceOptions,\n schedulePersonaInstance,\n type UpgradeSingletonOptions,\n type UpgradeSingletonResult,\n upgradeSingletonToDefaultPersona,\n} from './persona-instance.js';\nexport {\n availabilityFromResolvedAgent,\n type ManifestPersonaDefaults,\n type PersonaAvailabilityGate,\n type PersonaContext,\n PersonaResolver,\n type ResolvedPersona,\n type ResolvePersonaOptions,\n} from './persona-resolver.js';\nexport {\n type DirectiveDraft,\n type DirectiveReflector,\n type ReflectionInput,\n type ReflectionPersona,\n type ReflectionPersonaInput,\n ReflectionRunner,\n type ReflectionRunnerOptions,\n type ReflectionRunOptions,\n type ReflectionRunResult,\n} from './reflection-runner.js';\n\n// Contribute the persona directive-activation permission to the runtime catalog\n// on import, so any consumer of this package sees the gate's slug.\nensurePersonaPermissionsRegistered();\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["tenantId"],"sources":["../src/__smrt-register__.ts","../src/directive-principal.ts","../src/agent-persona.ts","../src/directive-proposal.ts","../src/feedback.ts","../src/persona-prompt.ts","../src/directive-approval.ts","../src/persona-instance.ts","../src/persona-memory.ts","../src/persona-resolver.ts","../src/reflection-runner.ts","../src/index.ts"],"sourcesContent":["import { ObjectRegistry } from '@happyvertical/smrt-core';\n\nObjectRegistry.registerPackageManifest(\n new URL('./manifest.json', import.meta.url),\n);\n","/**\n * The permission split that gates persona directive activation (#1889).\n *\n * **The gate is the permission system, not a bespoke subsystem.** Activating a\n * directive — writing/enabling the persona-scoped `prompt_override` — is a\n * permissioned operation guarded by the `personas.activate-directive` slug. The\n * autonomous reflection principal runs *without* that permission, so it can only\n * propose; a human who holds it approves / edits / rejects. Confidence-only\n * reinforcement stays automatic; only instruction rewrites are gated.\n *\n * This module contributes the slug to the manifest-derived permission catalog\n * (via `registerPermissionDefinitions`) and provides a small\n * {@link DirectivePrincipal} abstraction over \"which permission slugs does this\n * actor hold\". In production the principal is built from a\n * `PermissionResolver.resolvePermissions()` result; tests inject one directly.\n *\n * @module\n */\n\nimport {\n type PermissionDefinition,\n type PermissionResolver,\n registerPermissionDefinitions,\n} from '@happyvertical/smrt-users';\n\n/** The permission slug that authorises activating a persona directive. */\nexport const ACTIVATE_DIRECTIVE_PERMISSION = 'personas.activate-directive';\n\n/** Catalog definition contributed for {@link ACTIVATE_DIRECTIVE_PERMISSION}. */\nexport const DIRECTIVE_ACTIVATION_PERMISSION_DEF: PermissionDefinition = {\n slug: ACTIVATE_DIRECTIVE_PERMISSION,\n category: 'personas',\n name: 'Activate Persona Directive',\n description:\n \"Approve, edit, or reject a proposed edit to a persona's instructions and activate the persona-scoped prompt override\",\n};\n\n/**\n * An actor whose authority is expressed as a set of held permission slugs.\n *\n * Deliberately minimal so the gate depends only on the permission model, not on\n * any particular resolver or session machinery.\n */\nexport interface DirectivePrincipal {\n /** Optional stable id (recorded as the reviewer on approve/reject). */\n readonly id?: string;\n /**\n * The tenant this principal's authority was resolved for. Permissions are\n * resolved per tenant (`PermissionResolver.resolvePermissions(userId, tenantId)`),\n * so a principal authorised in one tenant must not activate another tenant's\n * directive. When set, the approval service enforces\n * `principal.tenantId === proposal.tenantId`. `undefined` skips the check\n * (e.g. a system/global actor or a hand-built principal).\n */\n readonly tenantId?: string;\n /** Whether this actor holds the given permission slug. */\n can(slug: string): boolean;\n}\n\n/**\n * Build a {@link DirectivePrincipal} from an explicit set of granted slugs.\n */\nexport function principalFromPermissions(\n permissions: Iterable<string>,\n options: { id?: string; tenantId?: string } = {},\n): DirectivePrincipal {\n const granted = new Set(permissions);\n return {\n id: options.id,\n tenantId: options.tenantId,\n can: (slug: string) => granted.has(slug),\n };\n}\n\n/**\n * Build a {@link DirectivePrincipal} for a user in a tenant by resolving their\n * effective permissions through the RBAC {@link PermissionResolver} — the\n * production wiring that makes the gate concretely the permission system.\n */\nexport async function resolveDirectivePrincipal(options: {\n resolver: PermissionResolver;\n userId: string;\n tenantId: string;\n}): Promise<DirectivePrincipal> {\n const { permissions } = await options.resolver.resolvePermissions(\n options.userId,\n options.tenantId,\n );\n // Carry the resolved tenant so the approval service can refuse a directive\n // from a different tenant (permissions were resolved for this tenant only).\n return principalFromPermissions(permissions, {\n id: options.userId,\n tenantId: options.tenantId,\n });\n}\n\nlet personaPermissionsRegistered = false;\n\n/**\n * Register the persona directive-activation permission into the runtime catalog.\n *\n * @returns An unregister function (primarily for tests).\n */\nexport function registerPersonaPermissions(): () => void {\n return registerPermissionDefinitions([DIRECTIVE_ACTIVATION_PERMISSION_DEF]);\n}\n\n/**\n * Register the persona permissions once per process. Called as a side effect\n * from the package entry so the slug is present in the permission catalog for\n * any consumer that imports `@happyvertical/smrt-personas`.\n */\nexport function ensurePersonaPermissionsRegistered(): void {\n if (personaPermissionsRegistered) {\n return;\n }\n personaPermissionsRegistered = true;\n registerPersonaPermissions();\n}\n","/**\n * AgentPersona - Tenant-owned, context-scoped persona for an agent class.\n *\n * A persona layers behavioral configuration on top of a {@link TenantAgent}\n * binding (from `@happyvertical/smrt-agents`). Where `TenantAgent` answers\n * \"is this agent available for the tenant, and what is its capability ceiling\",\n * an `AgentPersona` answers \"how should this agent behave for this tenant in\n * this context\" — its instructions, allowed tools, run-as principal, acting\n * identity, and memory scope.\n *\n * There can be many personas per `(tenant, agentClass)` — one per context\n * (e.g. a site, property, or chat room) plus optional tenant-wide defaults.\n * Personas are unique on `(tenant_id, agent_class, name)`.\n *\n * Resolution (context + hierarchy + priority) lives in {@link PersonaResolver};\n * this class is the persisted record and its CRUD collection only.\n */\n\nimport {\n crossPackageRef,\n field,\n getClassName,\n ObjectRegistry,\n SmrtCollection,\n SmrtObject,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\n\n/**\n * Return the canonical agent type identifier for storage and lookup.\n *\n * Uses the registry's qualified name when the class is registered and falls\n * back to the raw input for dynamically defined or unregistered classes. This\n * mirrors `getAgentTypeName()` in `@happyvertical/smrt-agents` without reaching\n * into that package's internal module — personas store the same canonical form\n * that `TenantAgent` does so the two layers line up.\n */\nexport function canonicalAgentClass(name: string): string {\n const registered = ObjectRegistry.getClass(name);\n return registered?.qualifiedName || registered?.name || name;\n}\n\n/**\n * Return the meaningful aliases for an agent class — the canonical qualified\n * name plus the simple class name — deduplicated.\n *\n * Lookups match against both so a persona persisted under a simple name (e.g.\n * `Praeco`, when written through the generated create API without\n * normalization) is still found when resolving under the canonical qualified\n * name, and vice versa. Mirrors `getAgentTypeAliases()` in\n * `@happyvertical/smrt-agents`.\n */\nexport function agentClassAliases(name: string): string[] {\n const registered = ObjectRegistry.getClass(name);\n const canonical = registered?.qualifiedName || registered?.name || name;\n const simple = registered?.name || getClassName(name);\n return Array.from(new Set([canonical, simple].filter(Boolean)));\n}\n\n/**\n * Parse a JSON-array-of-strings stored as text, tolerating malformed input.\n */\nfunction parseStringArray(raw: string | null | undefined): string[] {\n if (!raw) {\n return [];\n }\n try {\n const parsed = JSON.parse(raw);\n return Array.isArray(parsed)\n ? parsed.filter((value): value is string => typeof value === 'string')\n : [];\n } catch {\n return [];\n }\n}\n\n/**\n * AgentPersona SmrtObject — a tenant/context-scoped behavioral profile for an\n * agent class.\n */\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'agent_personas',\n api: { include: ['list', 'get', 'create', 'update', 'delete'] },\n cli: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n conflictColumns: ['tenant_id', 'agent_class', 'name'],\n})\nexport class AgentPersona extends SmrtObject {\n /** Owning tenant (required — personas are never global). */\n @tenantId()\n tenantId: string = '';\n\n /**\n * Canonical qualified agent type this persona configures\n * (e.g. `@happyvertical/smrt-agents:Praeco`). Stored in canonical form so it\n * lines up with `TenantAgent.agentClass`.\n */\n @field({ type: 'text' })\n agentClass: string = '';\n\n /**\n * Human-readable persona name, unique per `(tenant, agentClass)`\n * (see `conflictColumns`). Inherited `name` from {@link SmrtObject} is the\n * conflict column; declared here for documentation and typing clarity.\n */\n name: string = '';\n\n /**\n * Optional context dimension type this persona is scoped to\n * (e.g. `'site'`, `'property'`, `'chatRoom'`). `null` means the persona is a\n * tenant-wide default that applies to every context for its agent class.\n */\n @field({ type: 'text', nullable: true })\n contextType: string | null = null;\n\n /**\n * Optional context dimension id. Only meaningful alongside `contextType`:\n * when set, the persona targets one specific context row; when `null` (with\n * a `contextType` set) it applies to every context of that type.\n */\n @field({ type: 'text', nullable: true })\n contextId: string | null = null;\n\n /** System prompt / behavioral instructions layered onto the agent. */\n @field({ type: 'text' })\n instructions: string = '';\n\n /**\n * Allowed tool identifiers, stored as a JSON array string. Use\n * {@link getAllowedTools} / {@link setAllowedTools} rather than reading this\n * field directly. Empty array (`'[]'`) means \"no persona-specific tools\"\n * (the resolver then falls back to manifest defaults, capped by the\n * `TenantAgent` ceiling).\n */\n @field({ type: 'text' })\n allowedTools: string = '[]';\n\n /**\n * The user whose principal this persona runs as (cross-package reference to\n * `@happyvertical/smrt-users:User`). Required — a persona always runs as a\n * concrete principal. Stored as a plain id column; no DDL FK constraint is\n * emitted (cross-package).\n */\n @crossPackageRef('@happyvertical/smrt-users:User', { required: true })\n runAsUserId: string = '';\n\n /**\n * Optional `Bot` profile the persona acts as for identity/audit\n * (cross-package reference to `@happyvertical/smrt-profiles:Profile`).\n * `null` when the persona has no distinct acting identity.\n */\n @crossPackageRef('@happyvertical/smrt-profiles:Profile', { nullable: true })\n actsAsProfileId: string | null = null;\n\n /**\n * Memory scope key controlling how the agent's memory/reflection is\n * partitioned for this persona. Empty string means \"use a resolver-derived\n * default\".\n */\n @field({ type: 'text' })\n memoryScope: string = '';\n\n /**\n * Resolution priority — higher wins when several personas apply to the same\n * context at the same tenant level. Integer.\n */\n priority: number = 0;\n\n /** Whether this persona is active and eligible for resolution. */\n @field({ type: 'boolean' })\n enabled: boolean = true;\n\n /**\n * Allowed tool identifiers as an array.\n *\n * Tolerates malformed stored JSON by returning an empty array.\n */\n getAllowedTools(): string[] {\n return parseStringArray(this.allowedTools);\n }\n\n /**\n * Replace the allowed tool identifiers.\n */\n setAllowedTools(tools: string[]): void {\n this.allowedTools = JSON.stringify(tools ?? []);\n }\n}\n\n/**\n * Collection for managing {@link AgentPersona} records.\n */\nexport class AgentPersonaCollection extends SmrtCollection<AgentPersona> {\n static readonly _itemClass = AgentPersona;\n\n /**\n * List personas for a tenant + agent class, matching either the canonical\n * qualified name or the simple class name (see {@link agentClassAliases}).\n *\n * Ordered by descending priority then name.\n *\n * @param extraWhere - Additional equality filters merged into the query\n * (e.g. `{ enabled: true }`).\n */\n private async listForClass(\n tenantId: string,\n agentClass: string,\n extraWhere: Record<string, unknown> = {},\n ): Promise<AgentPersona[]> {\n const aliases = agentClassAliases(agentClass);\n const where =\n aliases.length > 1\n ? { tenantId, 'agentClass in': aliases, ...extraWhere }\n : { tenantId, agentClass: aliases[0], ...extraWhere };\n const personas = await this.list({ where });\n return sortByPriorityThenName(personas);\n }\n\n /**\n * List every persona bound to a tenant + agent class.\n *\n * Ordered by descending priority then name so callers that don't need the\n * full resolver still get a deterministic, priority-first ordering.\n */\n async byTenantAndClass(\n tenantId: string,\n agentClass: string,\n ): Promise<AgentPersona[]> {\n return this.listForClass(tenantId, agentClass);\n }\n\n /**\n * List the enabled personas for a tenant + agent class, filtered to those\n * applicable to a context.\n *\n * `enabled` is filtered in the query; the context predicate (tenant-wide vs\n * type-scoped vs exact) is applied in memory since it is an OR over several\n * columns. A persona is applicable when it is a tenant-wide default (no\n * `contextType`) or its context matches the requested one. Ordered by\n * descending priority then name.\n *\n * @param context - Optional `{ contextType, contextId }` to filter by.\n */\n async findActive(\n tenantId: string,\n agentClass: string,\n context: { contextType?: string | null; contextId?: string | null } = {},\n ): Promise<AgentPersona[]> {\n const personas = await this.listForClass(tenantId, agentClass, {\n enabled: true,\n });\n return personas.filter((persona) =>\n personaAppliesToContext(persona, context),\n );\n }\n}\n\n/**\n * Whether a persona applies to a requested context.\n *\n * - No `contextType` on the persona → tenant-wide default, applies to all.\n * - `contextType` set, `contextId` null → type-scoped, applies when the\n * requested `contextType` matches.\n * - Both set → exact, applies when both match.\n */\nexport function personaAppliesToContext(\n persona: Pick<AgentPersona, 'contextType' | 'contextId'>,\n context: { contextType?: string | null; contextId?: string | null },\n): boolean {\n if (!persona.contextType) {\n return true;\n }\n if (persona.contextType !== (context.contextType ?? null)) {\n return false;\n }\n if (persona.contextId == null) {\n return true;\n }\n return persona.contextId === (context.contextId ?? null);\n}\n\n/**\n * Context-specificity rank used for resolution ordering.\n *\n * - `2` exact `(contextType, contextId)` match\n * - `1` type-scoped match (`contextType` matches, persona `contextId` null)\n * - `0` tenant-wide default (persona has no `contextType`)\n */\nexport function personaContextRank(\n persona: Pick<AgentPersona, 'contextType' | 'contextId'>,\n): number {\n if (!persona.contextType) {\n return 0;\n }\n return persona.contextId == null ? 1 : 2;\n}\n\nfunction sortByPriorityThenName(personas: AgentPersona[]): AgentPersona[] {\n return [...personas].sort((a, b) => {\n if (b.priority !== a.priority) {\n return b.priority - a.priority;\n }\n return (a.name ?? '').localeCompare(b.name ?? '');\n });\n}\n\nexport default AgentPersona;\n","/**\n * DirectiveProposal — a pending, human-reviewable edit to a persona's\n * instructions (#1889).\n *\n * The autonomous {@link ReflectionRunner} consolidates recent episodes and\n * {@link Feedback} into candidate rewrites of a persona's instructions and\n * records each as a pending `DirectiveProposal` (rationale + evidence). A\n * proposal is inert data: it changes nothing until a human who holds the\n * `personas.activate-directive` permission approves it through the review\n * queue, at which point the persona-scoped `prompt_override` is written.\n *\n * The reflection principal deliberately lacks that permission, so it can only\n * *propose* — the permission split is the gate. See {@link DirectiveApprovalService}.\n *\n * @module\n */\n\nimport {\n field,\n foreignKey,\n SmrtCollection,\n SmrtObject,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\n\n/**\n * Lifecycle status of a proposal:\n *\n * - `pending` — awaiting review; surfaced in the queue.\n * - `approved` — a reviewer activated it; the override was written.\n * - `rejected` — a reviewer declined it; recorded as a signal and never\n * re-surfaced (the runner dedups against it by fingerprint).\n * - `superseded` — a newer proposal replaced it before review.\n */\nexport type DirectiveProposalStatus =\n | 'pending'\n | 'approved'\n | 'rejected'\n | 'superseded';\n\n/**\n * Structured evidence backing a proposal — the ids of the learning episodes and\n * feedback signals the reflection consolidated. Pure references so the proposal\n * stays auditable without duplicating payloads.\n */\nexport interface DirectiveEvidence {\n /** `_smrt_contexts` row ids of the episodes considered. */\n episodeIds?: string[];\n /** {@link Feedback} row ids considered. */\n feedbackIds?: string[];\n /** Free-form supporting notes (e.g. counts, aggregate metrics). */\n notes?: string[];\n [key: string]: unknown;\n}\n\n/**\n * A stable content fingerprint for `(personaId, promptKey, proposedInstructions)`.\n *\n * Used to dedup proposals so an already-reviewed rewrite — in particular a\n * rejected one — is never re-surfaced. Pure FNV-1a so it needs no crypto import\n * and stays identical across Node and browser bundles.\n */\nexport function computeDirectiveFingerprint(\n personaId: string,\n promptKey: string,\n proposedInstructions: string,\n): string {\n const input = `${personaId} ${promptKey} ${proposedInstructions}`;\n let hash = 0x811c9dc5;\n for (let i = 0; i < input.length; i++) {\n hash ^= input.charCodeAt(i);\n // FNV prime multiply, kept in 32-bit unsigned space.\n hash = Math.imul(hash, 0x01000193) >>> 0;\n }\n return hash.toString(16).padStart(8, '0');\n}\n\nfunction parseEvidence(raw: unknown): DirectiveEvidence {\n if (typeof raw !== 'string' || raw.length === 0) {\n return raw && typeof raw === 'object' ? (raw as DirectiveEvidence) : {};\n }\n try {\n const parsed = JSON.parse(raw);\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed)\n ? (parsed as DirectiveEvidence)\n : {};\n } catch {\n return {};\n }\n}\n\n/**\n * A pending, human-reviewable proposed edit to a persona's instructions.\n */\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'directive_proposals',\n // Read-only generated surface: activation/rejection go through the\n // permission-gated DirectiveApprovalService, not generated CRUD writes.\n api: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n})\nexport class DirectiveProposal extends SmrtObject {\n /** Owning tenant (required — proposals always target a tenant's persona). */\n @tenantId()\n tenantId: string = '';\n\n /** The persona whose instructions this proposal would rewrite. */\n @foreignKey('AgentPersona', { required: true })\n personaId: string = '';\n\n /** Canonical agent class the persona configures (denormalised for queries). */\n @field({ type: 'text' })\n agentClass: string = '';\n\n /**\n * The registered prompt key whose template the persona's instructions map to.\n * Activation writes/updates the tenant-scoped override for this key.\n */\n @field({ type: 'text' })\n promptKey: string = '';\n\n /** The proposed replacement instructions (the new prompt template). */\n @field({ type: 'text' })\n proposedInstructions: string = '';\n\n /** Snapshot of the instructions at proposal time (for a review diff). */\n @field({ type: 'text' })\n currentInstructions: string = '';\n\n /** Model-authored explanation for the proposed change. */\n @field({ type: 'text' })\n rationale: string = '';\n\n /** Structured evidence, stored as a JSON string (see {@link getEvidence}). */\n @field({ type: 'text' })\n evidence: string = '{}';\n\n /** Lifecycle status. */\n @field({ type: 'text' })\n status: DirectiveProposalStatus = 'pending';\n\n /**\n * Content fingerprint for dedup / not-re-surfacing. Set from\n * {@link computeDirectiveFingerprint} at creation time.\n */\n @field({ type: 'text' })\n fingerprint: string = '';\n\n /** Aggregate confidence in the proposal, in `[0, 1]`. */\n confidence: number = 0.0;\n\n /** Id of the principal (autonomous reflection actor) that proposed it. */\n @field({ type: 'text' })\n proposedBy: string = '';\n\n /** The reviewer (user id) that approved/rejected it, once reviewed. */\n @field({ type: 'text', nullable: true })\n reviewedBy: string | null = null;\n\n /** When the proposal was reviewed. */\n @field({ type: 'datetime', nullable: true })\n reviewedAt: Date | null = null;\n\n /** Reviewer note attached on approve/reject. */\n @field({ type: 'text', nullable: true })\n reviewNote: string | null = null;\n\n /** The `prompt_override` id written on activation (`null` until approved). */\n @field({ type: 'text', nullable: true })\n activatedOverrideId: string | null = null;\n\n /** Parse {@link evidence}, tolerating malformed JSON. */\n getEvidence(): DirectiveEvidence {\n return parseEvidence(this.evidence);\n }\n\n /** Replace {@link evidence}. */\n setEvidence(value: DirectiveEvidence): void {\n this.evidence = JSON.stringify(value ?? {});\n }\n\n /** Whether the proposal is still awaiting review. */\n isPending(): boolean {\n return this.status === 'pending';\n }\n}\n\n/**\n * Collection for {@link DirectiveProposal} rows — the review queue.\n */\nexport class DirectiveProposalCollection extends SmrtCollection<DirectiveProposal> {\n static readonly _itemClass = DirectiveProposal;\n\n /**\n * The review queue: pending proposals, oldest first. Optionally scoped to a\n * persona.\n */\n async pending(\n options: { personaId?: string; limit?: number } = {},\n ): Promise<DirectiveProposal[]> {\n const where: Record<string, unknown> = { status: 'pending' };\n if (options.personaId) {\n where.personaId = options.personaId;\n }\n return this.list({\n where,\n orderBy: 'created_at ASC',\n limit: options.limit,\n });\n }\n\n /**\n * Existing proposals for a persona carrying a given fingerprint, in any\n * status — used to avoid re-surfacing an already-seen (e.g. rejected) rewrite.\n */\n async findByFingerprint(\n personaId: string,\n fingerprint: string,\n ): Promise<DirectiveProposal[]> {\n return this.list({ where: { personaId, fingerprint } });\n }\n}\n\nexport default DirectiveProposal;\n","/**\n * Feedback — reinforcement signals for a persona's learning loop (#1889).\n *\n * A `Feedback` row captures one reinforcement signal against a persona and the\n * `LearningMemory` episode it pertains to. Two families of signal are modelled:\n *\n * - **Human signals** — `accept` / `reject` / `correction` / `rating`: an\n * operator's judgement on an agent's behaviour.\n * - **Autonomous signals** — `outcome` / `metric`: a machine-observed result\n * (a boolean success or a numeric measurement) captured without a human.\n *\n * Every signal carries a **correlation-id** back to the thing it judges — the\n * AI call, dispatch, or job whose result prompted the feedback — so a signal\n * can always be traced to its cause. Signals feed the confidence-scored\n * reinforcement in {@link LearningMemory} (#1886) via {@link toLearningOutcome}:\n * this is the automatic, confidence-only half of the loop. The gated half —\n * rewriting a persona's instructions — lives in the directive-proposal flow.\n *\n * @module\n */\n\nimport {\n field,\n foreignKey,\n type LearningOutcome,\n SmrtCollection,\n SmrtObject,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\n\n/**\n * The kind of reinforcement signal a {@link Feedback} row carries.\n *\n * `accept` / `reject` / `correction` / `rating` are human judgements;\n * `outcome` / `metric` are machine-observed autonomous signals.\n */\nexport type FeedbackSignalType =\n | 'accept'\n | 'reject'\n | 'correction'\n | 'rating'\n | 'outcome'\n | 'metric';\n\n/** Whether a signal originated from a person or an autonomous observation. */\nexport type FeedbackSource = 'human' | 'autonomous';\n\n/** The human-authored signal types. */\nexport const HUMAN_SIGNAL_TYPES: readonly FeedbackSignalType[] = [\n 'accept',\n 'reject',\n 'correction',\n 'rating',\n];\n\n/**\n * Return the natural source for a signal type: the human judgement types are\n * `'human'`; `outcome` / `metric` are `'autonomous'`.\n */\nexport function feedbackSourceFor(signal: FeedbackSignalType): FeedbackSource {\n return HUMAN_SIGNAL_TYPES.includes(signal) ? 'human' : 'autonomous';\n}\n\n/** Options for {@link Feedback.toLearningOutcome}. */\nexport interface FeedbackOutcomeOptions {\n /**\n * The neutral point of a `rating` scale. A rating strictly above the neutral\n * reinforces as a success; at or below it decays as a failure. Default `0`\n * (any positive rating is a success), matching {@link LearningOutcome}'s\n * metric convention. Pass e.g. `3` for a 1–5 star scale.\n */\n ratingNeutral?: number;\n}\n\nfunction parseJsonObject(raw: unknown): Record<string, unknown> {\n if (typeof raw !== 'string' || raw.length === 0) {\n return raw && typeof raw === 'object'\n ? (raw as Record<string, unknown>)\n : {};\n }\n try {\n const parsed = JSON.parse(raw);\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : {};\n } catch {\n return {};\n }\n}\n\n/**\n * A single reinforcement signal against a persona and a learning episode.\n */\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'agent_feedback',\n api: { include: ['list', 'get', 'create'] },\n cli: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n})\nexport class Feedback extends SmrtObject {\n /** Owning tenant (optional — autonomous signals may be tenant-less). */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /** The persona this signal judges. */\n @foreignKey('AgentPersona', { required: true })\n personaId: string = '';\n\n /** Canonical agent class the persona configures (denormalised for queries). */\n @field({ type: 'text' })\n agentClass: string = '';\n\n /**\n * Memory scope the signal reinforces — the partition key routing it to the\n * right {@link LearningMemory} so different personas reinforce independently.\n */\n @field({ type: 'text' })\n memoryScope: string = '';\n\n /** Learning episode scope this signal pertains to (`LearningEpisode.scope`). */\n @field({ type: 'text' })\n scope: string = '';\n\n /** Learning episode key this signal pertains to (`LearningEpisode.key`). */\n @field({ type: 'text' })\n key: string = '';\n\n /** The kind of signal (see {@link FeedbackSignalType}). */\n @field({ type: 'text' })\n signalType: FeedbackSignalType = 'outcome';\n\n /** Whether the signal is human or autonomous. */\n @field({ type: 'text' })\n source: FeedbackSource = 'autonomous';\n\n /**\n * Correlation-id back to the thing this signal judges — the AI call,\n * dispatch, or job id. Required so a signal is always traceable to its cause.\n */\n @field({ type: 'text', required: true })\n correlationId: string = '';\n\n /**\n * What kind of thing {@link correlationId} names (e.g. `'ai_call'`,\n * `'dispatch'`, `'job'`). `null` when the namespace is implicit.\n */\n @field({ type: 'text', nullable: true })\n correlationType: string | null = null;\n\n /** Numeric rating for a `rating` signal (scale is caller-defined). */\n @field({ type: 'decimal', nullable: true })\n rating: number | null = null;\n\n /** Observed measurement for a `metric` signal. */\n @field({ type: 'decimal', nullable: true })\n metric: number | null = null;\n\n /** Observed boolean result for an `outcome` signal. */\n @field({ type: 'boolean', nullable: true })\n success: boolean | null = null;\n\n /**\n * Corrected instructions/value for a `correction` signal — the human-supplied\n * replacement that should supersede the strategy that was judged wrong.\n */\n @field({ type: 'text', nullable: true })\n correction: string | null = null;\n\n /** Freeform note attached to the signal. */\n @field({ type: 'text', nullable: true })\n comment: string | null = null;\n\n /** The user id that authored a human signal (`null` for autonomous). */\n @field({ type: 'text', nullable: true })\n actorId: string | null = null;\n\n /** Arbitrary structured metadata, stored as a JSON string. */\n @field({ type: 'text' })\n metadata: string = '{}';\n\n /**\n * When this signal was applied to memory as reinforcement. `null` until a\n * reflection pass consumes it. Gates exactly-once reinforcement so a scheduled\n * runner never re-applies the same signal (which would amplify a single\n * accept/reject into many outcomes).\n */\n @field({ type: 'datetime', nullable: true })\n reinforcedAt: Date | null = null;\n\n /** Whether this is a human-authored signal. */\n isHuman(): boolean {\n return this.source === 'human';\n }\n\n /** Parse {@link metadata}, tolerating malformed JSON. */\n getMetadata(): Record<string, unknown> {\n return parseJsonObject(this.metadata);\n }\n\n /** Replace {@link metadata}. */\n setMetadata(value: Record<string, unknown>): void {\n this.metadata = JSON.stringify(value ?? {});\n }\n\n /** Shallow-merge into {@link metadata}. */\n updateMetadata(patch: Record<string, unknown>): void {\n this.setMetadata({ ...this.getMetadata(), ...patch });\n }\n\n /**\n * The strategy value a `correction` signal should persist into memory, so a\n * regenerated (corrected) strategy supersedes the one that was judged wrong.\n * `undefined` for non-correction signals (reinforce confidence only).\n */\n getCorrectionValue(): string | undefined {\n return this.signalType === 'correction' && this.correction != null\n ? this.correction\n : undefined;\n }\n\n /**\n * Map this signal onto a {@link LearningOutcome} for reinforcement, or `null`\n * when the signal carries no reinforcement value:\n *\n * - `accept` → success; `reject` / `correction` → failure.\n * - `outcome` → the recorded boolean `success`.\n * - `metric` → the recorded `metric` (positive → success).\n * - `rating` → `{ metric: rating - ratingNeutral }`.\n */\n toLearningOutcome(\n options: FeedbackOutcomeOptions = {},\n ): LearningOutcome | null {\n switch (this.signalType) {\n case 'accept':\n return { success: true };\n case 'reject':\n case 'correction':\n return { success: false, error: this.comment ?? undefined };\n case 'outcome':\n return this.success == null ? null : { success: this.success };\n case 'metric':\n return this.metric == null ? null : { metric: this.metric };\n case 'rating': {\n if (this.rating == null) {\n return null;\n }\n return { metric: this.rating - (options.ratingNeutral ?? 0) };\n }\n default:\n return null;\n }\n }\n}\n\n/**\n * Collection for {@link Feedback} rows.\n */\nexport class FeedbackCollection extends SmrtCollection<Feedback> {\n static readonly _itemClass = Feedback;\n\n /** All signals for a persona, newest first. */\n async forPersona(\n personaId: string,\n options: { limit?: number } = {},\n ): Promise<Feedback[]> {\n return this.list({\n where: { personaId },\n orderBy: 'created_at DESC',\n limit: options.limit,\n });\n }\n\n /** All signals filed under a memory scope, newest first. */\n async forScope(\n memoryScope: string,\n options: { limit?: number } = {},\n ): Promise<Feedback[]> {\n return this.list({\n where: { memoryScope },\n orderBy: 'created_at DESC',\n limit: options.limit,\n });\n }\n\n /** Every signal correlated to a given AI call / dispatch / job id. */\n async byCorrelation(correlationId: string): Promise<Feedback[]> {\n return this.list({\n where: { correlationId },\n orderBy: 'created_at DESC',\n });\n }\n}\n\nexport default Feedback;\n","/**\n * Persona ↔ prompt-override binding (#1889).\n *\n * A persona's `instructions` are applied to the running agent through a\n * **tenant/persona-scoped `prompt_override`**, not by mutating the agent's code\n * default. Each persona owns a dedicated, per-persona prompt key registered at\n * runtime with a neutral empty base template; the persona's actual instructions\n * live entirely in the override layer. Because the key is unique per persona,\n * two personas of the same tenant and agent class resolve to different\n * instructions without colliding on the `(key, context)` override identity.\n *\n * Activating a directive (see {@link DirectiveApprovalService}) is exactly the\n * act of writing/updating this override — and it flows through\n * `PromptOverride.save()`, so `validatePromptOverride` still forbids overriding\n * a non-editable prompt field.\n *\n * @module\n */\n\nimport {\n definePrompt,\n type PromptDefinition,\n type PromptEditableConfig,\n type PromptOverride,\n PromptOverrideCollection,\n PromptRegistry,\n resolvePrompt,\n} from '@happyvertical/smrt-prompts';\nimport type { DatabaseInterface } from '@happyvertical/sql';\n\n/** The minimal persona shape these helpers need. */\nexport interface PersonaLike {\n id?: string | null;\n tenantId?: string | null;\n instructions?: string;\n}\n\n/**\n * The registered prompt key a persona's instructions map to.\n *\n * @throws if the persona has no id (an unsaved persona has no stable key).\n */\nexport function personaInstructionsPromptKey(persona: PersonaLike): string {\n const id = persona.id;\n if (!id) {\n throw new Error(\n 'personaInstructionsPromptKey requires a persisted persona (missing id)',\n );\n }\n return `persona.${id}.instructions`;\n}\n\n/** Default editability for a persona instructions prompt: template-only. */\nconst DEFAULT_PERSONA_EDITABLE: PromptEditableConfig = {\n template: true,\n profile: false,\n model: false,\n params: false,\n};\n\n/**\n * Idempotently register the per-persona instructions prompt.\n *\n * The base template is always the empty string and the editability is fixed, so\n * repeated calls register an identical definition (the registry is idempotent\n * for matching definitions). The persona's real instructions are supplied by\n * the override layer, never by the base template — that keeps re-registration\n * stable even as instructions change.\n *\n * Pass `editable` to model a prompt whose template is locked; activation of a\n * proposal against such a key is then rejected by `validatePromptOverride`.\n */\nexport function ensurePersonaInstructionsPrompt(\n persona: PersonaLike,\n options: { editable?: Partial<PromptEditableConfig> } = {},\n): PromptDefinition {\n const key = personaInstructionsPromptKey(persona);\n const existing = PromptRegistry.get(key);\n // Fast path only when the caller does not assert a specific editability. When\n // `editable` IS given, always go through definePrompt so a conflicting\n // re-registration (e.g. trying to lock `template: false` over an already\n // editable key) is rejected loudly rather than silently ignored.\n if (existing && options.editable === undefined) {\n return existing;\n }\n return definePrompt({\n key,\n template: '',\n editable: { ...DEFAULT_PERSONA_EDITABLE, ...(options.editable ?? {}) },\n });\n}\n\n/**\n * Upsert a scoped `prompt_override` template for a registered prompt key.\n *\n * Loads the existing app/tenant override (by `tenantId`), updates its template,\n * or creates a new one. Always flows through `PromptOverride.save()`, so\n * `validatePromptOverride` still forbids overriding a non-editable template.\n *\n * The prompt key must already be registered (via\n * {@link ensurePersonaInstructionsPrompt} or `definePrompt`); this helper does\n * not register it, so it never silently relaxes a locked prompt's editability.\n *\n * @returns The persisted override.\n */\nexport async function upsertPromptTemplateOverride(options: {\n db: DatabaseInterface;\n key: string;\n tenantId: string | null;\n template: string;\n}): Promise<PromptOverride> {\n const { db, key, tenantId, template } = options;\n const overrides = await PromptOverrideCollection.create({ db });\n const existing =\n tenantId != null\n ? await overrides.getTenantOverride(key, tenantId)\n : await overrides.getAppOverride(key);\n\n if (existing) {\n existing.template = template;\n await existing.save();\n return existing;\n }\n\n return overrides.create({ key, tenantId, template });\n}\n\n/**\n * Write (or update) the tenant-scoped `prompt_override` that carries a persona's\n * instructions.\n *\n * Ensures the per-persona prompt key is registered, then upserts the override\n * template to `instructions ?? persona.instructions`. Flows through\n * `PromptOverride.save()`, so a non-editable template throws.\n *\n * @returns The persisted override.\n */\nexport async function applyPersonaInstructions(options: {\n persona: PersonaLike;\n db: DatabaseInterface;\n instructions?: string;\n editable?: Partial<PromptEditableConfig>;\n}): Promise<PromptOverride> {\n const { persona, db } = options;\n ensurePersonaInstructionsPrompt(persona, { editable: options.editable });\n return upsertPromptTemplateOverride({\n db,\n key: personaInstructionsPromptKey(persona),\n tenantId: persona.tenantId ?? null,\n template: options.instructions ?? persona.instructions ?? '',\n });\n}\n\n/**\n * Resolve a persona's effective instructions through the prompt system —\n * layering code default → config → app override → tenant (persona) override.\n *\n * @returns The rendered instructions text (empty string when nothing overrides\n * the neutral base template).\n */\nexport async function resolvePersonaInstructions(options: {\n persona: PersonaLike;\n db: DatabaseInterface;\n variables?: Record<string, unknown>;\n}): Promise<string> {\n const { persona, db } = options;\n ensurePersonaInstructionsPrompt(persona);\n const key = personaInstructionsPromptKey(persona);\n const resolved = await resolvePrompt(key, {\n db,\n tenantId: persona.tenantId ?? null,\n variables: options.variables,\n });\n return resolved.text;\n}\n","/**\n * DirectiveApprovalService — the human-in-the-loop gate (#1889).\n *\n * The review queue's write side. A reviewer who holds the\n * `personas.activate-directive` permission can **approve** (optionally editing\n * the text), or **reject**, a pending {@link DirectiveProposal}:\n *\n * - **approve** activates the persona-scoped `prompt_override` (through\n * `PromptOverride.save()`, so a non-editable prompt template is refused by\n * `validatePromptOverride`) and records an `accept` signal.\n * - **reject** records a `reject` signal and closes the proposal so the\n * reflection runner never re-surfaces the same rewrite (it dedups on\n * fingerprint against non-pending proposals too).\n *\n * The gate is purely the permission check: an actor lacking the slug — the\n * autonomous reflection principal included — is denied before anything is\n * written. Confidence-only reinforcement is unaffected; it never passes here.\n *\n * @module\n */\n\nimport type { PromptOverride } from '@happyvertical/smrt-prompts';\nimport type { DatabaseInterface } from '@happyvertical/sql';\nimport { AgentPersonaCollection } from './agent-persona.js';\nimport {\n ACTIVATE_DIRECTIVE_PERMISSION,\n type DirectivePrincipal,\n} from './directive-principal.js';\nimport {\n DirectiveProposal,\n DirectiveProposalCollection,\n} from './directive-proposal.js';\nimport { type Feedback, FeedbackCollection } from './feedback.js';\nimport { upsertPromptTemplateOverride } from './persona-prompt.js';\n\n/** Raised when a principal without the activation permission attempts to review. */\nexport class DirectiveActivationDeniedError extends Error {\n constructor(\n message = `Principal lacks the '${ACTIVATE_DIRECTIVE_PERMISSION}' permission required to review persona directives`,\n ) {\n super(message);\n this.name = 'DirectiveActivationDeniedError';\n }\n}\n\n/** Raised when a review is attempted on a proposal that is not pending. */\nexport class DirectiveNotPendingError extends Error {\n constructor(status: string) {\n super(`Directive proposal is not pending (status: ${status})`);\n this.name = 'DirectiveNotPendingError';\n }\n}\n\n/** Options for {@link DirectiveApprovalService}. */\nexport interface DirectiveApprovalServiceOptions {\n db: DatabaseInterface;\n proposals?: DirectiveProposalCollection;\n feedback?: FeedbackCollection;\n personas?: AgentPersonaCollection;\n}\n\n/** Result of approving a proposal. */\nexport interface DirectiveApprovalResult {\n proposal: DirectiveProposal;\n /** The activated persona-scoped override. */\n override: PromptOverride;\n /** The recorded `accept` signal. */\n signal: Feedback;\n}\n\n/** Result of rejecting a proposal. */\nexport interface DirectiveRejectionResult {\n proposal: DirectiveProposal;\n /** The recorded `reject` signal. */\n signal: Feedback;\n}\n\n/** A proposal reference: the row, or its id. */\nexport type ProposalRef = DirectiveProposal | string;\n\n/**\n * The permission-gated review surface for persona directives.\n */\nexport class DirectiveApprovalService {\n private readonly db: DatabaseInterface;\n private proposals?: DirectiveProposalCollection;\n private feedback?: FeedbackCollection;\n private personas?: AgentPersonaCollection;\n\n constructor(options: DirectiveApprovalServiceOptions) {\n this.db = options.db;\n this.proposals = options.proposals;\n this.feedback = options.feedback;\n this.personas = options.personas;\n }\n\n /**\n * Assert a principal is authorised to review directives. The single gate:\n * everything privileged in this service calls it first.\n *\n * @throws {DirectiveActivationDeniedError} when the principal lacks the slug.\n */\n assertCanActivate(principal: DirectivePrincipal): void {\n if (!principal.can(ACTIVATE_DIRECTIVE_PERMISSION)) {\n throw new DirectiveActivationDeniedError();\n }\n }\n\n /**\n * Assert a principal may review a specific proposal: its resolved tenant, when\n * bound, must match the proposal's tenant. Permissions are resolved per\n * tenant, so holding the slug in one tenant must not authorise activating\n * another tenant's directive.\n *\n * @throws {DirectiveActivationDeniedError} on a cross-tenant attempt.\n */\n private assertTenantMatch(\n principal: DirectivePrincipal,\n proposal: DirectiveProposal,\n ): void {\n if (\n principal.tenantId !== undefined &&\n principal.tenantId !== proposal.tenantId\n ) {\n throw new DirectiveActivationDeniedError(\n `Principal (tenant '${principal.tenantId}') cannot review a directive for tenant '${proposal.tenantId}'`,\n );\n }\n }\n\n /**\n * Approve a pending proposal: activate the persona-scoped override and record\n * an `accept` signal. Pass `editedInstructions` to activate a revised text\n * (the proposal keeps the model's original as its audit record; the override\n * holds what was activated).\n *\n * @throws {DirectiveActivationDeniedError} when the principal lacks the slug.\n * @throws {DirectiveNotPendingError} when the proposal is already reviewed.\n */\n async approve(\n ref: ProposalRef,\n principal: DirectivePrincipal,\n options: { note?: string; editedInstructions?: string } = {},\n ): Promise<DirectiveApprovalResult> {\n this.assertCanActivate(principal);\n const proposal = await this.loadPending(ref);\n this.assertTenantMatch(principal, proposal);\n\n const template =\n options.editedInstructions ?? proposal.proposedInstructions;\n\n // Activation is exactly writing the persona-scoped override. This flows\n // through PromptOverride.save() → validatePromptOverride, so a non-editable\n // template is refused here (the error propagates to the reviewer).\n const override = await upsertPromptTemplateOverride({\n db: this.db,\n key: proposal.promptKey,\n tenantId: proposal.tenantId,\n template,\n });\n\n // Keep the persona's own `instructions` field in sync with the activated\n // text, so the field-based `PersonaResolver.resolve()` path reflects the\n // approved directive too — not only the prompt-override path. Best effort:\n // the override is the authoritative application; a missing persona (e.g.\n // deleted) does not fail the activation.\n await this.syncPersonaInstructions(proposal.personaId, template);\n\n proposal.status = 'approved';\n proposal.reviewedBy = principal.id ?? null;\n proposal.reviewedAt = new Date();\n proposal.reviewNote = options.note ?? null;\n proposal.activatedOverrideId = override.id ?? null;\n await proposal.save();\n\n const signal = await this.recordSignal(proposal, 'accept', principal, {\n note: options.note,\n edited: options.editedInstructions !== undefined,\n });\n\n return { proposal, override, signal };\n }\n\n /**\n * Reject a pending proposal: record a `reject` signal and close it so it is\n * never re-surfaced.\n *\n * @throws {DirectiveActivationDeniedError} when the principal lacks the slug.\n * @throws {DirectiveNotPendingError} when the proposal is already reviewed.\n */\n async reject(\n ref: ProposalRef,\n principal: DirectivePrincipal,\n options: { note?: string } = {},\n ): Promise<DirectiveRejectionResult> {\n this.assertCanActivate(principal);\n const proposal = await this.loadPending(ref);\n this.assertTenantMatch(principal, proposal);\n\n proposal.status = 'rejected';\n proposal.reviewedBy = principal.id ?? null;\n proposal.reviewedAt = new Date();\n proposal.reviewNote = options.note ?? null;\n await proposal.save();\n\n const signal = await this.recordSignal(proposal, 'reject', principal, {\n note: options.note,\n });\n\n return { proposal, signal };\n }\n\n private async loadPending(ref: ProposalRef): Promise<DirectiveProposal> {\n const proposal =\n ref instanceof DirectiveProposal ? ref : await this.getProposal(ref);\n if (!proposal) {\n throw new Error(`Directive proposal not found: ${String(ref)}`);\n }\n if (proposal.status !== 'pending') {\n throw new DirectiveNotPendingError(proposal.status);\n }\n return proposal;\n }\n\n private async getProposal(id: string): Promise<DirectiveProposal | null> {\n const proposals = await this.proposalsCollection();\n return proposals.get({ id });\n }\n\n private async recordSignal(\n proposal: DirectiveProposal,\n signalType: 'accept' | 'reject',\n principal: DirectivePrincipal,\n options: { note?: string; edited?: boolean } = {},\n ): Promise<Feedback> {\n const feedback = await this.feedbackCollection();\n return feedback.create({\n tenantId: proposal.tenantId,\n personaId: proposal.personaId,\n agentClass: proposal.agentClass,\n memoryScope: '',\n scope: 'persona/directive',\n key: proposal.id ?? '',\n signalType,\n source: 'human',\n // The correlation-id ties the signal back to the reviewed proposal.\n correlationId: proposal.id ?? '',\n correlationType: 'directive_proposal',\n actorId: principal.id ?? null,\n comment: options.note ?? null,\n metadata: JSON.stringify({ edited: options.edited ?? false }),\n });\n }\n\n private async syncPersonaInstructions(\n personaId: string,\n instructions: string,\n ): Promise<void> {\n const personas = await this.personasCollection();\n const persona = await personas.get({ id: personaId });\n if (!persona) {\n return;\n }\n persona.instructions = instructions;\n await persona.save();\n }\n\n private async personasCollection(): Promise<AgentPersonaCollection> {\n if (!this.personas) {\n this.personas = await AgentPersonaCollection.create({ db: this.db });\n }\n return this.personas;\n }\n\n private async proposalsCollection(): Promise<DirectiveProposalCollection> {\n if (!this.proposals) {\n this.proposals = await DirectiveProposalCollection.create({\n db: this.db,\n });\n }\n return this.proposals;\n }\n\n private async feedbackCollection(): Promise<FeedbackCollection> {\n if (!this.feedback) {\n this.feedback = await FeedbackCollection.create({ db: this.db });\n }\n return this.feedback;\n }\n}\n","/**\n * Persona-as-durable-instance helpers (#1890).\n *\n * Treats an {@link AgentPersona} as a **durable instance** of an agent class:\n * N configured instances per tenant, each independently scheduled, memory-scoped,\n * and permission-scoped. This module wires that instance concept to the\n * `@happyvertical/smrt-agents` runtime:\n *\n * - **Identity** — {@link personaInstanceKey} / {@link agentOptionsForPersona}\n * map a persona to the `AgentOptions.instanceKey` the framework folds into a\n * per-instance dispatch subscriber, memory scope, and interest scope. The\n * `default` persona reuses the **singleton** identity (a `null` key), which is\n * what makes the singleton→multi upgrade non-destructive.\n * - **Scheduling** — {@link schedulePersonaInstance} binds an `AgentSchedule` to\n * a persona instance, routing the instance key through `agentConfig` so it\n * reaches the constructed agent as `AgentOptions.instanceKey`.\n * - **Admin** — {@link buildPersonaInstanceAdmin} renders the agent class's\n * `uiSlots`/`adminRoutes` once per instance, with {@link addPersonaInstance} /\n * {@link removePersonaInstance} affordances.\n * - **Upgrade** — {@link upgradeSingletonToDefaultPersona} maps an existing\n * singleton to a single `default` persona without touching its data.\n *\n * Multi-instance is a per-package opt-in on the agent class\n * (`static multiInstance = true`); these helpers manage the persona rows that\n * back it. A singleton (non-opted) agent needs none of this and is unchanged.\n */\n\nimport {\n type AgentAdminRoute,\n type AgentManifestInfo,\n type AgentSchedule,\n type AgentScheduleCollection,\n type AgentUISlots,\n instanceScopedSubscriber,\n} from '@happyvertical/smrt-agents';\nimport {\n type AgentPersona,\n type AgentPersonaCollection,\n canonicalAgentClass,\n} from './agent-persona.js';\n\n/**\n * The reserved persona name for the singleton/default instance.\n *\n * Matches the `PersonaResolver` default-fallback name so the concept is\n * consistent across the package. A persona with this name is the tenant's\n * singleton identity: it maps to a `null` instance key (see\n * {@link personaInstanceKey}), reusing the class-keyed dispatch subscriber and\n * un-suffixed memory scope an un-upgraded agent already uses.\n */\nexport const DEFAULT_PERSONA_NAME = 'default';\n\n/**\n * The durable per-instance key for a persona, or `null` for the singleton.\n *\n * - The `default` persona → `null`: it *is* the singleton identity, so an agent\n * run as it keeps the class-keyed dispatch subscriber and un-suffixed memory\n * scope. This is why upgrading a singleton to a default persona changes no\n * runtime identity (non-destructive).\n * - Any other persona → its `id`: a distinct, stable instance key the framework\n * folds into a per-instance subscriber/memory/interest scope.\n *\n * @throws Error if a non-default persona has no `id` (it must be saved first —\n * an unsaved non-default persona would masquerade as the singleton).\n */\nexport function personaInstanceKey(\n persona: Pick<AgentPersona, 'name' | 'id'>,\n): string | null {\n if (persona.name === DEFAULT_PERSONA_NAME) {\n return null;\n }\n if (!persona.id) {\n throw new Error(\n 'personaInstanceKey: a non-default persona must be saved (have an id) ' +\n 'before it can act as a durable instance',\n );\n }\n return persona.id;\n}\n\n/**\n * Whether a persona is the singleton/default instance.\n */\nexport function isDefaultPersona(persona: Pick<AgentPersona, 'name'>): boolean {\n return persona.name === DEFAULT_PERSONA_NAME;\n}\n\n/**\n * The subset of `AgentOptions` a runtime spreads to construct an agent as this\n * persona instance. Kept structural (no agents runtime import needed by the\n * caller) — spread into `new AgentClass({ ...agentOptionsForPersona(p), db })`.\n */\nexport interface PersonaAgentOptions {\n /** Per-instance key — `null` for the default (singleton) persona. */\n instanceKey: string | null;\n /** The tenant the persona belongs to. */\n tenantId: string;\n}\n\n/**\n * Project a persona into the agent construction options that give the agent its\n * per-instance identity.\n */\nexport function agentOptionsForPersona(\n persona: AgentPersona,\n): PersonaAgentOptions {\n return {\n instanceKey: personaInstanceKey(persona),\n tenantId: persona.tenantId,\n };\n}\n\n/**\n * Options for {@link schedulePersonaInstance}.\n */\nexport interface SchedulePersonaInstanceOptions {\n /** Cron expression (5-field). */\n cron: string;\n /** Timezone label (default `'UTC'`). */\n timezone?: string;\n /** Agent method to invoke (default `'run'`). */\n method?: string;\n /** Config passed to the agent on each run. */\n agentConfig?: Record<string, unknown>;\n /** Arguments passed to the method. */\n methodArgs?: Record<string, unknown>;\n /** Whether the schedule starts enabled (default `true`). */\n enabled?: boolean;\n}\n\n/**\n * Create an `AgentSchedule` bound to a persona **instance**.\n *\n * The schedule's `agentType` is the persona's agent class. The persona instance\n * key ({@link personaInstanceKey}) must reach the constructed agent as\n * `AgentOptions.instanceKey`, so it is carried in `agentConfig` — which the\n * scheduler (`smrt-jobs`) spreads into the agent constructor options — and\n * `agentId` is left **null**.\n *\n * This is deliberate: the scheduler copies `AgentSchedule.agentId` to\n * `SmrtJob.objectId`, and the `TaskRunner` `loadFromId()`s a non-null\n * `objectId` against the agent's STI table. A persona id lives in\n * `agent_personas`, not that table, so putting it in `agentId` would fail to\n * load (or load the wrong row). Leaving `agentId` null makes the runner\n * construct a fresh instance and pick up `instanceKey` from `agentConfig`. The\n * default persona (null key) carries no key → runs the singleton.\n *\n * @param schedules - The `AgentScheduleCollection` to create into.\n * @param persona - The persona instance to schedule (must be saved).\n * @param options - Cron and run settings.\n */\nexport async function schedulePersonaInstance(\n schedules: AgentScheduleCollection,\n persona: AgentPersona,\n options: SchedulePersonaInstanceOptions,\n): Promise<AgentSchedule> {\n const instanceKey = personaInstanceKey(persona);\n const agentConfig: Record<string, unknown> = {\n ...(options.agentConfig ?? {}),\n };\n if (instanceKey) {\n agentConfig.instanceKey = instanceKey;\n }\n const schedule = await schedules.create({\n tenantId: persona.tenantId,\n agentType: persona.agentClass,\n agentId: null,\n cron: options.cron,\n timezone: options.timezone ?? 'UTC',\n method: options.method ?? 'run',\n agentConfig,\n methodArgs: options.methodArgs ?? {},\n enabled: options.enabled ?? true,\n });\n await schedule.save();\n return schedule;\n}\n\n/**\n * One instance's row in the instance-aware admin surface.\n *\n * Carries the agent class's admin surface (`slots` / `adminRoutes`) rendered for\n * THIS instance, plus the resolved per-instance dispatch subscriber so the admin\n * can show how the instance is routed.\n */\nexport interface PersonaInstanceView {\n /** The persona id backing this instance. */\n personaId: string;\n /** Persona (instance) name. */\n name: string;\n /** Per-instance key — `null` for the default (singleton). */\n instanceKey: string | null;\n /** Whether this is the default (singleton) instance. */\n isDefault: boolean;\n /** Whether the instance is enabled. */\n enabled: boolean;\n /** Resolution priority. */\n priority: number;\n /** Context scoping (if any). */\n contextType: string | null;\n contextId: string | null;\n /** The principal the instance runs as. */\n runAsUserId: string;\n /** Optional acting bot identity. */\n actsAsProfileId: string | null;\n /** The per-instance dispatch subscriber identity. */\n dispatchSubscriber: string;\n /** The agent class's UI slots, rendered for this instance. */\n slots: AgentUISlots;\n /** The agent class's admin routes, rendered for this instance. */\n adminRoutes: AgentAdminRoute[];\n}\n\n/**\n * The instance-aware admin surface for one `(tenant, agentClass)` pair.\n */\nexport interface PersonaInstanceAdminView {\n /** Canonical agent class the surface is for. */\n agentClass: string;\n /** Tenant the surface is for. */\n tenantId: string;\n /** One entry per configured instance (persona), priority-ordered. */\n instances: PersonaInstanceView[];\n /** Whether new instances may be added (always true for the persona model). */\n canAddInstance: boolean;\n}\n\n/**\n * Options for {@link buildPersonaInstanceAdmin}.\n */\nexport interface BuildPersonaInstanceAdminOptions {\n /** Tenant to render the surface for. */\n tenantId: string;\n /** Agent class (canonicalized internally). */\n agentClass: string;\n /**\n * The agent class's manifest surface. Its `uiSlots` / `adminRoutes` are\n * rendered once per instance. Optional — omit to render instances with empty\n * panels (e.g. a class that declares none).\n */\n manifest?: Pick<AgentManifestInfo, 'uiSlots' | 'adminRoutes'>;\n}\n\n/**\n * Build the instance-aware admin surface: one panel set per configured instance.\n *\n * Lists the tenant's persona instances for the class and renders the class's\n * `uiSlots`/`adminRoutes` for each, so an admin sees N instances (not one class\n * panel) with add/remove affordances. The default (singleton) instance appears\n * with `instanceKey: null` and the class-keyed subscriber.\n *\n * @param personas - Persona collection to read instances from.\n * @param options - Tenant, class, and the class manifest to render per instance.\n */\nexport async function buildPersonaInstanceAdmin(\n personas: AgentPersonaCollection,\n options: BuildPersonaInstanceAdminOptions,\n): Promise<PersonaInstanceAdminView> {\n const canonical = canonicalAgentClass(options.agentClass);\n const slots = options.manifest?.uiSlots ?? {};\n const adminRoutes = options.manifest?.adminRoutes ?? [];\n\n const rows = await personas.byTenantAndClass(options.tenantId, canonical);\n\n const instances: PersonaInstanceView[] = rows.map((persona) => {\n const instanceKey = personaInstanceKey(persona);\n return {\n personaId: persona.id as string,\n name: persona.name,\n instanceKey,\n isDefault: isDefaultPersona(persona),\n enabled: persona.enabled,\n priority: persona.priority,\n contextType: persona.contextType,\n contextId: persona.contextId,\n runAsUserId: persona.runAsUserId,\n actsAsProfileId: persona.actsAsProfileId,\n dispatchSubscriber: instanceScopedSubscriber(canonical, instanceKey),\n slots,\n adminRoutes,\n };\n });\n\n return {\n agentClass: canonical,\n tenantId: options.tenantId,\n instances,\n canAddInstance: true,\n };\n}\n\n/**\n * Options for {@link addPersonaInstance}.\n */\nexport interface AddPersonaInstanceOptions {\n tenantId: string;\n agentClass: string;\n /** Instance name (unique per `(tenant, agentClass)`). */\n name: string;\n /** The principal the instance runs as (required by `AgentPersona`). */\n runAsUserId: string;\n instructions?: string;\n allowedTools?: string[];\n contextType?: string | null;\n contextId?: string | null;\n priority?: number;\n memoryScope?: string;\n actsAsProfileId?: string | null;\n enabled?: boolean;\n}\n\n/**\n * Add a new instance (persona) — the \"add\" admin affordance.\n *\n * Creates and saves an `AgentPersona`, canonicalizing the agent class so it\n * lines up with `TenantAgent`. The `(tenant_id, agent_class, name)` unique\n * constraint rejects a duplicate name.\n */\nexport async function addPersonaInstance(\n personas: AgentPersonaCollection,\n options: AddPersonaInstanceOptions,\n): Promise<AgentPersona> {\n const persona = await personas.create({\n tenantId: options.tenantId,\n agentClass: canonicalAgentClass(options.agentClass),\n name: options.name,\n instructions: options.instructions ?? '',\n contextType: options.contextType ?? null,\n contextId: options.contextId ?? null,\n priority: options.priority ?? 0,\n enabled: options.enabled ?? true,\n runAsUserId: options.runAsUserId,\n actsAsProfileId: options.actsAsProfileId ?? null,\n memoryScope: options.memoryScope ?? '',\n });\n if (options.allowedTools) {\n persona.setAllowedTools(options.allowedTools);\n }\n await persona.save();\n return persona;\n}\n\n/**\n * Remove an instance (persona) by id — the \"remove\" admin affordance.\n *\n * Deletes only the named instance; other instances of the class are untouched.\n * A no-op (returns `false`) when the persona does not exist.\n *\n * @returns `true` if a persona was removed, `false` if none matched the id.\n */\nexport async function removePersonaInstance(\n personas: AgentPersonaCollection,\n personaId: string,\n): Promise<boolean> {\n const persona = await personas.get({ id: personaId });\n if (!persona) {\n return false;\n }\n await persona.delete();\n return true;\n}\n\n/**\n * Options for {@link upgradeSingletonToDefaultPersona}.\n */\nexport interface UpgradeSingletonOptions {\n tenantId: string;\n agentClass: string;\n /** The principal the default persona runs as (required by `AgentPersona`). */\n runAsUserId: string;\n /** Instructions to seed the default persona with (from existing config). */\n instructions?: string;\n /** Tools to seed (from existing config). */\n allowedTools?: string[];\n /**\n * Memory scope for the default persona. Leave empty (default) to let the\n * resolver derive it — for the default (null-keyed) instance the derived\n * scope equals the singleton's existing `agent/<type>` scope, so existing\n * learned memory is preserved untouched.\n */\n memoryScope?: string;\n actsAsProfileId?: string | null;\n}\n\n/**\n * The result of a singleton→multi upgrade.\n */\nexport interface UpgradeSingletonResult {\n /** The default persona representing the existing singleton instance. */\n persona: AgentPersona;\n /** `true` if it was created now, `false` if a default persona already existed. */\n created: boolean;\n /**\n * The instance key for the default persona — always `null`, i.e. it maps to\n * the existing singleton runtime identity (same dispatch subscriber + memory\n * scope), which is what makes the upgrade non-destructive.\n */\n instanceKey: null;\n}\n\n/**\n * Non-destructively upgrade a singleton agent to the multi-instance model by\n * mapping the existing instance to a single `default` persona.\n *\n * The default persona is null-keyed, so it *reuses the singleton's exact runtime\n * identity* — the class-keyed dispatch subscriber and the un-suffixed\n * `agent/<type>` memory scope. Nothing about the running agent, its config, its\n * dispatch subscriptions, or its learned memory changes; a persona row is simply\n * added so further instances can now be created alongside it.\n *\n * Idempotent: if a `default` persona already exists for the pair it is returned\n * with `created: false` and nothing is duplicated.\n *\n * @param personas - Persona collection to read/create into.\n * @param options - Tenant, class, and the principal + config to seed.\n */\nexport async function upgradeSingletonToDefaultPersona(\n personas: AgentPersonaCollection,\n options: UpgradeSingletonOptions,\n): Promise<UpgradeSingletonResult> {\n const canonical = canonicalAgentClass(options.agentClass);\n\n const existing = await personas.byTenantAndClass(options.tenantId, canonical);\n const existingDefault = existing.find(isDefaultPersona);\n if (existingDefault) {\n return { persona: existingDefault, created: false, instanceKey: null };\n }\n\n const persona = await addPersonaInstance(personas, {\n tenantId: options.tenantId,\n agentClass: canonical,\n name: DEFAULT_PERSONA_NAME,\n runAsUserId: options.runAsUserId,\n instructions: options.instructions,\n allowedTools: options.allowedTools,\n memoryScope: options.memoryScope,\n actsAsProfileId: options.actsAsProfileId,\n priority: 0,\n enabled: true,\n });\n\n return { persona, created: true, instanceKey: null };\n}\n","/**\n * Persona-scoped learning memory routing (#1889).\n *\n * A persona's `memoryScope` routes {@link LearningMemory} so different personas\n * of the same agent class learn independently. The scope becomes the memory\n * partition (`owner_id`), so two personas never share confidence-scored\n * strategies even when they run the identical agent class over the same tenant.\n *\n * The other direction of the loop — turning a {@link Feedback} signal into a\n * confidence adjustment — is {@link reinforceFromFeedback}: the automatic,\n * confidence-only reinforcement that stays ungated (only instruction rewrites\n * are gated).\n *\n * @module\n */\n\nimport {\n LearningMemory,\n type LearningMemoryConfig,\n type LearningMemoryRecord,\n type LearningSemanticSearch,\n} from '@happyvertical/smrt-core';\nimport type { DatabaseInterface } from '@happyvertical/sql';\nimport type { Feedback, FeedbackOutcomeOptions } from './feedback.js';\n\n/** The minimal persona shape the memory router needs. */\nexport interface PersonaMemoryLike {\n id?: string | null;\n memoryScope?: string;\n agentClass?: string;\n tenantId?: string | null;\n}\n\n/**\n * The effective memory partition key for a persona: its explicit `memoryScope`,\n * or a stable `persona:<id>` fallback when none is set.\n *\n * @throws if neither a `memoryScope` nor an id is available.\n */\nexport function personaMemoryScope(persona: PersonaMemoryLike): string {\n const explicit = persona.memoryScope?.trim();\n if (explicit) {\n return explicit;\n }\n if (persona.id) {\n return `persona:${persona.id}`;\n }\n throw new Error(\n 'personaMemoryScope requires a persona with a memoryScope or an id',\n );\n}\n\n/**\n * Build a {@link LearningMemory} partitioned to a persona's memory scope.\n *\n * The persona's `memoryScope` is used as the memory `owner_id`, so recall and\n * capture are isolated per persona. `owner_class` defaults to the persona's\n * agent class (falling back to `'AgentPersona'`).\n */\nexport function personaLearningMemory(options: {\n db: DatabaseInterface;\n persona: PersonaMemoryLike;\n ownerClass?: string;\n tenantId?: string | null;\n semanticSearch?: LearningSemanticSearch;\n config?: Partial<LearningMemoryConfig>;\n}): LearningMemory {\n const ownerClass =\n options.ownerClass ??\n (options.persona.agentClass?.trim() || 'AgentPersona');\n return new LearningMemory({\n db: options.db,\n ownerClass,\n ownerId: personaMemoryScope(options.persona),\n tenantId: options.tenantId ?? options.persona.tenantId ?? null,\n semanticSearch: options.semanticSearch,\n config: options.config,\n });\n}\n\n/**\n * Apply a single {@link Feedback} signal to a persona's memory as\n * confidence-only reinforcement.\n *\n * Maps the signal onto a `LearningOutcome` and captures it against the episode\n * the signal names (`feedback.scope` / `feedback.key`). A `correction` signal\n * additionally supersedes the stored strategy with the corrected value.\n *\n * @returns The updated/seeded memory record, or `null` when the signal carries\n * no reinforcement value (or there was nothing to reinforce).\n */\nexport async function reinforceFromFeedback(\n memory: LearningMemory,\n feedback: Feedback,\n options: FeedbackOutcomeOptions = {},\n): Promise<LearningMemoryRecord | null> {\n const outcome = feedback.toLearningOutcome(options);\n if (!outcome) {\n return null;\n }\n const value = feedback.getCorrectionValue();\n return memory.capture(\n {\n scope: feedback.scope,\n key: feedback.key,\n ...(value !== undefined ? { value } : {}),\n },\n outcome,\n );\n}\n","/**\n * PersonaResolver - resolves the active {@link AgentPersona} for a\n * `(tenant, agentClass, context)` request.\n *\n * Layering, bottom to top (each layer overrides the previous):\n *\n * 1. **Manifest defaults** — the agent's built-in instructions / tools /\n * memory scope (supplied by the caller as {@link ManifestPersonaDefaults}).\n * 2. **TenantAgent** — the tenant/class availability gate and capability\n * ceiling (supplied as a {@link PersonaAvailabilityGate}; build one from a\n * `ResolvedAgentAvailability` via {@link availabilityFromResolvedAgent}).\n * `TenantAgent` decides *whether* the agent runs and *caps* its tools;\n * it never sets instructions.\n * 3. **AgentPersona** — the tenant's own persona for the context: overrides\n * instructions, sets tools (within the ceiling), run-as principal, acting\n * identity, and memory scope.\n *\n * Tenant-hierarchy inheritance mirrors `TenantAgentCollection.resolveForTenant`:\n * the resolver walks from the requesting tenant up its ancestors (nearest\n * first). The nearest tenant level that has any applicable persona wins the\n * resolution (a closer level shadows a farther one); within that level the most\n * context-specific, highest-priority persona is selected. When no level has an\n * applicable persona a defined default is returned.\n *\n * The hierarchy walk reads personas across tenants, so `resolve()` is meant to\n * run in a system/admin path where cross-tenant reads are permitted (i.e. not\n * inside a strict per-tenant interceptor context) — the same expectation\n * `TenantAgentCollection.resolveForTenant` carries.\n */\n\nimport type { ResolvedAgentAvailability } from '@happyvertical/smrt-agents';\nimport {\n type AgentPersona,\n type AgentPersonaCollection,\n canonicalAgentClass,\n personaAppliesToContext,\n personaContextRank,\n} from './agent-persona.js';\n\n/**\n * The context a persona is being resolved for.\n */\nexport interface PersonaContext {\n /** Context dimension type (e.g. `'site'`). */\n contextType?: string | null;\n /** Context dimension id within `contextType`. */\n contextId?: string | null;\n}\n\n/**\n * Bottom-layer defaults for an agent class, typically derived from its build\n * manifest.\n */\nexport interface ManifestPersonaDefaults {\n /** Default system instructions when no persona overrides them. */\n instructions?: string;\n /** Default tool identifiers, capped by the availability ceiling. */\n allowedTools?: string[];\n /** Default memory scope. */\n memoryScope?: string;\n}\n\n/**\n * Middle-layer availability + capability ceiling, projected from a\n * `TenantAgent` resolution.\n */\nexport interface PersonaAvailabilityGate {\n /** Resolved `TenantAgent` status. `'disabled'` marks the persona unavailable. */\n status: 'active' | 'disabled';\n /**\n * Tool identifiers the tenant is permitted to grant. When set, resolved\n * `allowedTools` are intersected with this ceiling. `undefined` means no\n * ceiling (tools pass through unchanged).\n */\n toolCeiling?: string[];\n /** Tenant the binding was resolved from (provenance only). */\n sourceTenantId?: string;\n}\n\n/**\n * Options for {@link PersonaResolver.resolve}.\n */\nexport interface ResolvePersonaOptions {\n /**\n * Return ancestor tenant ids for a tenant, nearest parent first through to\n * the root — mirrors `TenantAgentCollection.resolveForTenant`. Omit for a\n * single-tenant resolution with no inheritance.\n */\n getAncestorIds?: (tenantId: string) => Promise<string[]>;\n /** Bottom-layer manifest defaults for the agent class. */\n manifestDefaults?: ManifestPersonaDefaults;\n /**\n * Middle-layer `TenantAgent` availability + ceiling. Omit to skip gating\n * (the result is always `available: true` with no tool ceiling).\n */\n availability?: PersonaAvailabilityGate | null;\n}\n\n/**\n * A fully resolved persona: the layered, ready-to-use configuration plus\n * provenance describing how it was resolved.\n */\nexport interface ResolvedPersona {\n /** Canonical qualified agent type the resolution was for. */\n agentClass: string;\n /** Tenant the resolution was requested for. */\n tenantId: string;\n /** Id of the selected persona, or `undefined` for the default fallback. */\n personaId?: string;\n /** Selected persona name, or `'default'` for the fallback. */\n name: string;\n /** Layered instructions (persona → manifest default). */\n instructions: string;\n /** Layered tool ids (persona/manifest tools, capped by the ceiling). */\n allowedTools: string[];\n /** Run-as user principal, if the selected persona sets one. */\n runAsUserId?: string;\n /** Acting `Bot` profile id, if the selected persona sets one. */\n actsAsProfileId?: string | null;\n /** Resolved memory scope (persona → manifest default → derived default). */\n memoryScope: string;\n /** Selected persona priority (`0` for the default fallback). */\n priority: number;\n /** Context type the resolution was requested for. */\n contextType?: string | null;\n /** Context id the resolution was requested for. */\n contextId?: string | null;\n /** Whether a persona matched (`'persona'`) or the default was used (`'default'`). */\n source: 'persona' | 'default';\n /** For a matched persona, whether it was the tenant's own or inherited. */\n personaSource?: 'explicit' | 'inherited';\n /** Tenant the matched persona came from (own tenant or an ancestor). */\n sourceTenantId?: string;\n /** Whether the `TenantAgent` gate reports the agent as available. */\n available: boolean;\n}\n\n/**\n * Project a `TenantAgent` resolution into a {@link PersonaAvailabilityGate}.\n *\n * This is the concrete bridge between the `@happyvertical/smrt-agents`\n * availability layer and the persona layer. Pass `toolPermissionPrefix` to\n * derive a tool ceiling from granted permission ids (permissions whose id\n * starts with the prefix become the ceiling, with the prefix stripped); omit it\n * to leave the ceiling open.\n *\n * @param resolved - A `ResolvedAgentAvailability` (or `null`/`undefined`).\n * @param options.toolPermissionPrefix - Permission-id prefix that marks\n * tool grants (e.g. `'tool:'`).\n * @returns A gate, or `null` when `resolved` is nullish.\n */\nexport function availabilityFromResolvedAgent(\n resolved: ResolvedAgentAvailability | null | undefined,\n options: { toolPermissionPrefix?: string } = {},\n): PersonaAvailabilityGate | null {\n if (!resolved) {\n return null;\n }\n\n const { toolPermissionPrefix } = options;\n let toolCeiling: string[] | undefined;\n if (toolPermissionPrefix) {\n toolCeiling = Object.entries(resolved.permissions ?? {})\n .filter(([id, granted]) => granted && id.startsWith(toolPermissionPrefix))\n .map(([id]) => id.slice(toolPermissionPrefix.length))\n // Sort for a stable, order-independent ceiling regardless of how the\n // permissions map was produced.\n .sort();\n }\n\n return {\n status: resolved.status,\n toolCeiling,\n sourceTenantId: resolved.sourceTenantId,\n };\n}\n\n/**\n * Resolves the active persona for a `(tenant, agentClass, context)` request.\n */\nexport class PersonaResolver {\n constructor(private readonly personas: AgentPersonaCollection) {}\n\n /**\n * Resolve the active persona.\n *\n * @param tenantId - Requesting tenant.\n * @param agentClass - Agent class (canonicalized internally).\n * @param context - Context dimension being resolved for.\n * @param options - Hierarchy walk, manifest defaults, and availability gate.\n * @returns The layered {@link ResolvedPersona} — either a matched persona or\n * the defined default fallback.\n */\n async resolve(\n tenantId: string,\n agentClass: string,\n context: PersonaContext = {},\n options: ResolvePersonaOptions = {},\n ): Promise<ResolvedPersona> {\n const canonical = canonicalAgentClass(agentClass);\n const { getAncestorIds, manifestDefaults, availability } = options;\n\n const ancestorIds = getAncestorIds ? await getAncestorIds(tenantId) : [];\n const levels = [tenantId, ...ancestorIds];\n\n for (let level = 0; level < levels.length; level++) {\n const levelTenantId = levels[level];\n const candidates = await this.personas.findActive(\n levelTenantId,\n canonical,\n context,\n );\n\n if (candidates.length === 0) {\n continue;\n }\n\n const winner = pickWinner(candidates);\n return this.layerPersona(winner, {\n canonical,\n tenantId,\n context,\n manifestDefaults,\n availability,\n personaSource: level === 0 ? 'explicit' : 'inherited',\n sourceTenantId: levelTenantId,\n });\n }\n\n return this.defaultResolution({\n canonical,\n tenantId,\n context,\n manifestDefaults,\n availability,\n });\n }\n\n private layerPersona(\n persona: AgentPersona,\n ctx: LayerContext & {\n personaSource: 'explicit' | 'inherited';\n sourceTenantId: string;\n },\n ): ResolvedPersona {\n const { manifestDefaults, availability } = ctx;\n const personaTools = persona.getAllowedTools();\n const baseTools =\n personaTools.length > 0\n ? personaTools\n : (manifestDefaults?.allowedTools ?? []);\n\n return {\n agentClass: ctx.canonical,\n tenantId: ctx.tenantId,\n personaId: persona.id ?? undefined,\n name: persona.name,\n instructions:\n persona.instructions || manifestDefaults?.instructions || '',\n allowedTools: applyCeiling(baseTools, availability),\n runAsUserId: persona.runAsUserId || undefined,\n actsAsProfileId: persona.actsAsProfileId ?? null,\n memoryScope: resolveMemoryScope(persona.memoryScope, ctx),\n priority: persona.priority,\n contextType: ctx.context.contextType ?? null,\n contextId: ctx.context.contextId ?? null,\n source: 'persona',\n personaSource: ctx.personaSource,\n sourceTenantId: ctx.sourceTenantId,\n available: isAvailable(availability),\n };\n }\n\n private defaultResolution(ctx: LayerContext): ResolvedPersona {\n const { manifestDefaults, availability } = ctx;\n return {\n agentClass: ctx.canonical,\n tenantId: ctx.tenantId,\n name: 'default',\n instructions: manifestDefaults?.instructions ?? '',\n allowedTools: applyCeiling(\n manifestDefaults?.allowedTools ?? [],\n availability,\n ),\n actsAsProfileId: null,\n memoryScope: resolveMemoryScope('', ctx),\n priority: 0,\n contextType: ctx.context.contextType ?? null,\n contextId: ctx.context.contextId ?? null,\n source: 'default',\n available: isAvailable(availability),\n };\n }\n}\n\ninterface LayerContext {\n canonical: string;\n tenantId: string;\n context: PersonaContext;\n manifestDefaults?: ManifestPersonaDefaults;\n availability?: PersonaAvailabilityGate | null;\n}\n\n/**\n * Pick the winning persona from candidates already known to apply to the\n * requested context and be enabled.\n *\n * Order: most context-specific first, then highest priority, then name for a\n * stable deterministic tie-break.\n */\nfunction pickWinner(candidates: AgentPersona[]): AgentPersona {\n return [...candidates].sort((a, b) => {\n const rankDelta = personaContextRank(b) - personaContextRank(a);\n if (rankDelta !== 0) {\n return rankDelta;\n }\n if (b.priority !== a.priority) {\n return b.priority - a.priority;\n }\n return (a.name ?? '').localeCompare(b.name ?? '');\n })[0];\n}\n\nfunction applyCeiling(\n tools: string[],\n availability?: PersonaAvailabilityGate | null,\n): string[] {\n if (!availability?.toolCeiling) {\n return [...tools];\n }\n const ceiling = new Set(availability.toolCeiling);\n return tools.filter((tool) => ceiling.has(tool));\n}\n\nfunction isAvailable(availability?: PersonaAvailabilityGate | null): boolean {\n return availability ? availability.status === 'active' : true;\n}\n\nfunction resolveMemoryScope(explicit: string, ctx: LayerContext): string {\n if (explicit) {\n return explicit;\n }\n if (ctx.manifestDefaults?.memoryScope) {\n return ctx.manifestDefaults.memoryScope;\n }\n const contextSuffix = ctx.context.contextType\n ? `:${ctx.context.contextType}${ctx.context.contextId ? `:${ctx.context.contextId}` : ''}`\n : '';\n return `${ctx.canonical}:${ctx.tenantId}${contextSuffix}`;\n}\n\n// Re-export the context applicability helper for consumers building their own\n// persona selection UIs without duplicating the semantics.\nexport { personaAppliesToContext };\n","/**\n * ReflectionRunner — the scheduled consolidation step of the learning loop (#1889).\n *\n * Runs under the **autonomous reflection principal**, which deliberately lacks\n * the `personas.activate-directive` permission. For a persona it:\n *\n * 1. Applies recent {@link Feedback} to the persona's {@link LearningMemory}\n * as automatic, confidence-only reinforcement (ungated).\n * 2. Consolidates the resulting episodes + feedback and asks an injected\n * reflector (the AI boundary, mocked in tests) for a candidate rewrite of\n * the persona's instructions.\n * 3. Records that rewrite as a **pending** {@link DirectiveProposal} with\n * rationale + evidence — deduped by fingerprint so an already-seen (e.g.\n * rejected) rewrite is never re-surfaced.\n *\n * It cannot activate anything: writing the persona override is gated by the\n * permission its principal does not hold. That split is the whole gate.\n *\n * The runner is transport-agnostic; schedule it through an `AgentSchedule` /\n * background job by calling {@link run} on a cadence.\n *\n * @module\n */\n\nimport type {\n LearningMemory,\n LearningMemoryRecord,\n} from '@happyvertical/smrt-core';\nimport type { DatabaseInterface } from '@happyvertical/sql';\nimport type { DirectivePrincipal } from './directive-principal.js';\nimport {\n computeDirectiveFingerprint,\n type DirectiveProposal,\n DirectiveProposalCollection,\n} from './directive-proposal.js';\nimport { type Feedback, FeedbackCollection } from './feedback.js';\nimport { reinforceFromFeedback } from './persona-memory.js';\nimport {\n ensurePersonaInstructionsPrompt,\n personaInstructionsPromptKey,\n resolvePersonaInstructions,\n} from './persona-prompt.js';\n\n/** The (normalised) persona shape handed to the reflector. */\nexport interface ReflectionPersona {\n id: string;\n tenantId: string;\n agentClass?: string;\n name?: string;\n instructions?: string;\n memoryScope?: string;\n}\n\n/**\n * The persona a run consolidates over — accepts a persisted `AgentPersona`\n * directly (its `id` / `tenantId` are validated at run time).\n */\nexport interface ReflectionPersonaInput {\n id?: string | null;\n tenantId?: string | null;\n agentClass?: string;\n name?: string;\n instructions?: string;\n memoryScope?: string;\n}\n\n/** The consolidated input handed to the reflector (the AI boundary). */\nexport interface ReflectionInput {\n persona: ReflectionPersona;\n /** The persona's current effective instructions (resolved via prompts). */\n currentInstructions: string;\n /** Recent episodes for the persona's memory scope. */\n episodes: LearningMemoryRecord[];\n /** Recent feedback signals for the persona. */\n feedback: Feedback[];\n}\n\n/** A candidate rewrite returned by the reflector. */\nexport interface DirectiveDraft {\n /** Proposed replacement instructions. */\n instructions: string;\n /** Model-authored explanation. */\n rationale: string;\n /** Optional aggregate confidence in `[0, 1]`. */\n confidence?: number;\n}\n\n/**\n * The reflection boundary: consolidate episodes + feedback into a proposed\n * instruction rewrite, or `null` to propose nothing. Injected so the AI call is\n * the only thing mocked in tests.\n */\nexport type DirectiveReflector = (\n input: ReflectionInput,\n) => Promise<DirectiveDraft | null> | DirectiveDraft | null;\n\n/** Options for {@link ReflectionRunner}. */\nexport interface ReflectionRunnerOptions {\n db: DatabaseInterface;\n /** The autonomous principal — must NOT hold `personas.activate-directive`. */\n principal: DirectivePrincipal;\n /** The reflection boundary (AI call), injected. */\n reflect: DirectiveReflector;\n proposals?: DirectiveProposalCollection;\n feedback?: FeedbackCollection;\n /** Clock, injectable for deterministic lookback in tests. */\n now?: () => Date;\n}\n\n/** Options for a single {@link ReflectionRunner.run} pass over one persona. */\nexport interface ReflectionRunOptions {\n persona: ReflectionPersonaInput;\n /** The persona-scoped learning memory (see `personaLearningMemory`). */\n memory: LearningMemory;\n /** Episode scope to recall for evidence. Omit to skip episode gathering. */\n episodeScope?: string;\n /** Only consider feedback newer than this many ms ago. */\n lookbackMs?: number;\n /** Cap on feedback rows considered. Default 50. */\n feedbackLimit?: number;\n /** Neutral point for `rating` signals during reinforcement. Default 0. */\n ratingNeutral?: number;\n /** Override the target prompt key (default the persona instructions key). */\n promptKey?: string;\n}\n\n/** Result of a {@link ReflectionRunner.run} pass. */\nexport interface ReflectionRunResult {\n /** Newly created pending proposals (0 or 1). */\n proposals: DirectiveProposal[];\n /** Number of feedback signals that adjusted memory reinforcement. */\n reinforced: number;\n /** Number of candidate rewrites suppressed (deduped / no-op). */\n skipped: number;\n}\n\nfunction normalizePersona(input: ReflectionPersonaInput): ReflectionPersona {\n if (!input.id) {\n throw new Error(\n 'ReflectionRunner.run requires a persisted persona (missing id)',\n );\n }\n if (!input.tenantId) {\n throw new Error(\n 'ReflectionRunner.run requires a tenant-scoped persona (missing tenantId)',\n );\n }\n return {\n id: input.id,\n tenantId: input.tenantId,\n agentClass: input.agentClass,\n name: input.name,\n instructions: input.instructions,\n memoryScope: input.memoryScope,\n };\n}\n\nfunction meanConfidence(episodes: LearningMemoryRecord[]): number {\n if (episodes.length === 0) {\n return 0.5;\n }\n const sum = episodes.reduce((acc, e) => acc + e.confidence, 0);\n return sum / episodes.length;\n}\n\n/**\n * Consolidates feedback + episodes into pending directive proposals under a\n * principal that cannot activate them.\n */\nexport class ReflectionRunner {\n private readonly db: DatabaseInterface;\n private readonly reflect: DirectiveReflector;\n private readonly now: () => Date;\n private readonly _principal: DirectivePrincipal;\n private proposalsCol?: DirectiveProposalCollection;\n private feedbackCol?: FeedbackCollection;\n\n constructor(options: ReflectionRunnerOptions) {\n this.db = options.db;\n this._principal = options.principal;\n this.reflect = options.reflect;\n this.now = options.now ?? (() => new Date());\n this.proposalsCol = options.proposals;\n this.feedbackCol = options.feedback;\n }\n\n /**\n * The autonomous principal this runner acts as. Exposed so callers can prove\n * it cannot activate a proposal (it lacks `personas.activate-directive`).\n */\n get principal(): DirectivePrincipal {\n return this._principal;\n }\n\n /**\n * Run one reflection pass for a persona.\n */\n async run(options: ReflectionRunOptions): Promise<ReflectionRunResult> {\n const { memory } = options;\n const persona = normalizePersona(options.persona);\n const feedbackCol = await this.feedbackCollection();\n\n // 1. Recent feedback for the persona (optionally windowed).\n const feedbackLimit = options.feedbackLimit ?? 50;\n let feedback = await feedbackCol.forPersona(persona.id, {\n limit: feedbackLimit,\n });\n if (options.lookbackMs != null) {\n const cutoff = this.now().getTime() - options.lookbackMs;\n feedback = feedback.filter((f) => {\n const created = f.created_at ? new Date(f.created_at).getTime() : 0;\n return created >= cutoff;\n });\n }\n\n // 2. Automatic, confidence-only reinforcement — applied EXACTLY ONCE per\n // signal. A signal already consumed (`reinforcedAt` set) is skipped, so a\n // scheduled runner never re-applies it and amplifies one accept/reject\n // into many outcomes. Directive review signals (accept/reject of a\n // proposal) judge a proposal, not an episode, so they are marked consumed\n // without reinforcing.\n let reinforced = 0;\n for (const signal of feedback) {\n if (signal.reinforcedAt) {\n continue;\n }\n if (signal.correlationType !== 'directive_proposal') {\n const record = await reinforceFromFeedback(memory, signal, {\n ratingNeutral: options.ratingNeutral,\n });\n if (record) {\n reinforced += 1;\n }\n }\n signal.reinforcedAt = this.now();\n await signal.save();\n }\n\n // 3. Gather episodes as evidence (all confidences, including decayed ones).\n const episodes = options.episodeScope\n ? await memory.recall(options.episodeScope, {\n minConfidence: 0,\n includeAncestors: true,\n })\n : [];\n\n // 4. Resolve the persona's current instructions, then ask the reflector.\n ensurePersonaInstructionsPrompt(persona);\n const currentInstructions = await resolvePersonaInstructions({\n persona,\n db: this.db,\n });\n\n const draft = await this.reflect({\n persona,\n currentInstructions,\n episodes,\n feedback,\n });\n\n if (!draft || draft.instructions.trim() === currentInstructions.trim()) {\n // Nothing to propose, or a no-op rewrite.\n return { proposals: [], reinforced, skipped: draft ? 1 : 0 };\n }\n\n // 5. Dedup by fingerprint so an already-seen (e.g. rejected) rewrite is\n // never re-surfaced.\n const promptKey =\n options.promptKey ?? personaInstructionsPromptKey(persona);\n const fingerprint = computeDirectiveFingerprint(\n persona.id,\n promptKey,\n draft.instructions,\n );\n const proposals = await this.proposalsCollection();\n const existing = await proposals.findByFingerprint(persona.id, fingerprint);\n if (existing.length > 0) {\n return { proposals: [], reinforced, skipped: 1 };\n }\n\n // 6. Record the pending proposal (rationale + evidence). It is inert until a\n // permissioned human activates it.\n const proposal = await proposals.create({\n tenantId: persona.tenantId,\n personaId: persona.id,\n agentClass: persona.agentClass ?? '',\n promptKey,\n proposedInstructions: draft.instructions,\n currentInstructions,\n rationale: draft.rationale,\n status: 'pending',\n fingerprint,\n confidence: draft.confidence ?? meanConfidence(episodes),\n proposedBy: this._principal.id ?? 'reflection',\n evidence: JSON.stringify({\n episodeIds: episodes.map((e) => e.id),\n feedbackIds: feedback\n .map((f) => f.id)\n .filter((id): id is string => Boolean(id)),\n }),\n });\n\n return { proposals: [proposal], reinforced, skipped: 0 };\n }\n\n private async proposalsCollection(): Promise<DirectiveProposalCollection> {\n if (!this.proposalsCol) {\n this.proposalsCol = await DirectiveProposalCollection.create({\n db: this.db,\n });\n }\n return this.proposalsCol;\n }\n\n private async feedbackCollection(): Promise<FeedbackCollection> {\n if (!this.feedbackCol) {\n this.feedbackCol = await FeedbackCollection.create({ db: this.db });\n }\n return this.feedbackCol;\n }\n}\n","/**\n * @happyvertical/smrt-personas\n *\n * Tenant-owned, context-scoped agent personas and their resolution. Layers over\n * `@happyvertical/smrt-agents`' `TenantAgent` availability/ceiling gate to\n * decide how an agent should behave for a given tenant and context.\n *\n * Also home to the persona **learning & adaptation loop** (#1889): feedback\n * signals feed confidence-scored reinforcement, a scheduled reflection runner\n * consolidates episodes + feedback into pending directive proposals, and a\n * permission-gated approval service (the `personas.activate-directive` split)\n * activates an approved rewrite as a tenant/persona-scoped prompt override.\n *\n * @packageDocumentation\n */\n\n// Self-register this package's manifest before any @smrt() decorator fires\n// downstream. Must come first so the side effect runs ahead of the class\n// module loads below. See __smrt-register__.ts for issue #1132 context.\nimport './__smrt-register__.js';\n\nimport { ensurePersonaPermissionsRegistered } from './directive-principal.js';\n\nexport {\n AgentPersona,\n AgentPersonaCollection,\n canonicalAgentClass,\n personaAppliesToContext,\n personaContextRank,\n} from './agent-persona.js';\nexport {\n DirectiveActivationDeniedError,\n type DirectiveApprovalResult,\n DirectiveApprovalService,\n type DirectiveApprovalServiceOptions,\n DirectiveNotPendingError,\n type DirectiveRejectionResult,\n type ProposalRef,\n} from './directive-approval.js';\nexport {\n ACTIVATE_DIRECTIVE_PERMISSION,\n DIRECTIVE_ACTIVATION_PERMISSION_DEF,\n type DirectivePrincipal,\n ensurePersonaPermissionsRegistered,\n principalFromPermissions,\n registerPersonaPermissions,\n resolveDirectivePrincipal,\n} from './directive-principal.js';\nexport {\n computeDirectiveFingerprint,\n type DirectiveEvidence,\n DirectiveProposal,\n DirectiveProposalCollection,\n type DirectiveProposalStatus,\n} from './directive-proposal.js';\nexport {\n Feedback,\n FeedbackCollection,\n type FeedbackOutcomeOptions,\n type FeedbackSignalType,\n type FeedbackSource,\n feedbackSourceFor,\n HUMAN_SIGNAL_TYPES,\n} from './feedback.js';\nexport {\n type AddPersonaInstanceOptions,\n addPersonaInstance,\n agentOptionsForPersona,\n type BuildPersonaInstanceAdminOptions,\n buildPersonaInstanceAdmin,\n DEFAULT_PERSONA_NAME,\n isDefaultPersona,\n type PersonaAgentOptions,\n type PersonaInstanceAdminView,\n type PersonaInstanceView,\n personaInstanceKey,\n removePersonaInstance,\n type SchedulePersonaInstanceOptions,\n schedulePersonaInstance,\n type UpgradeSingletonOptions,\n type UpgradeSingletonResult,\n upgradeSingletonToDefaultPersona,\n} from './persona-instance.js';\nexport {\n type PersonaMemoryLike,\n personaLearningMemory,\n personaMemoryScope,\n reinforceFromFeedback,\n} from './persona-memory.js';\nexport {\n applyPersonaInstructions,\n ensurePersonaInstructionsPrompt,\n type PersonaLike,\n personaInstructionsPromptKey,\n resolvePersonaInstructions,\n upsertPromptTemplateOverride,\n} from './persona-prompt.js';\nexport {\n availabilityFromResolvedAgent,\n type ManifestPersonaDefaults,\n type PersonaAvailabilityGate,\n type PersonaContext,\n PersonaResolver,\n type ResolvedPersona,\n type ResolvePersonaOptions,\n} from './persona-resolver.js';\nexport {\n type DirectiveDraft,\n type DirectiveReflector,\n type ReflectionInput,\n type ReflectionPersona,\n type ReflectionPersonaInput,\n ReflectionRunner,\n type ReflectionRunnerOptions,\n type ReflectionRunOptions,\n type ReflectionRunResult,\n} from './reflection-runner.js';\n\n// Contribute the persona directive-activation permission to the runtime catalog\n// on import, so any consumer of this package sees the gate's slug.\nensurePersonaPermissionsRegistered();\n"],"mappings":"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"}
|
package/dist/manifest.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": "1.0.0",
|
|
3
|
-
"timestamp":
|
|
3
|
+
"timestamp": 1783721913682,
|
|
4
4
|
"packageName": "@happyvertical/smrt-personas",
|
|
5
|
-
"packageVersion": "0.
|
|
5
|
+
"packageVersion": "0.39.0",
|
|
6
6
|
"objects": {
|
|
7
7
|
"@happyvertical/smrt-personas:AgentPersona": {
|
|
8
8
|
"name": "agentpersona",
|
package/dist/smrt-knowledge.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"generatedAt": "2026-07-
|
|
3
|
+
"generatedAt": "2026-07-10T22:18:33.813Z",
|
|
4
4
|
"packageName": "@happyvertical/smrt-personas",
|
|
5
|
-
"packageVersion": "0.
|
|
5
|
+
"packageVersion": "0.39.0",
|
|
6
6
|
"sourceManifestPath": "dist/manifest.json",
|
|
7
7
|
"agentDocPath": "AGENTS.md",
|
|
8
8
|
"sourceHashes": {
|
|
9
|
-
"manifest": "
|
|
10
|
-
"packageJson": "
|
|
9
|
+
"manifest": "2b5ee1f7a696f33863c9050028e1c463ad797253d8adef9b0c5a3f23d6af21e5",
|
|
10
|
+
"packageJson": "9ff939ab351ed485dbdb5c6502bb8a3413a46fa1cc21782c055251ed11b00928",
|
|
11
11
|
"agents": "f35cdbfeae2e2235818031815c55c24c59eebbacc3aec00406f079d0f990abd3"
|
|
12
12
|
},
|
|
13
13
|
"exports": [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@happyvertical/smrt-personas",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.39.0",
|
|
4
4
|
"description": "Tenant-owned, context-scoped agent personas and resolution for the SMRT framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -23,19 +23,31 @@
|
|
|
23
23
|
"./manifest": "./dist/manifest.json",
|
|
24
24
|
"./manifest.json": "./dist/manifest.json"
|
|
25
25
|
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "vite build --mode library && svelte-package -i src/svelte -o dist/svelte --tsconfig tsconfig.svelte.json",
|
|
28
|
+
"build:watch": "vite build --mode library --watch",
|
|
29
|
+
"clean": "rm -rf dist",
|
|
30
|
+
"dev": "vite dev",
|
|
31
|
+
"prepack": "node ../../scripts/prepack-package.js",
|
|
32
|
+
"test": "vitest run",
|
|
33
|
+
"test:watch": "vitest",
|
|
34
|
+
"typecheck": "tsc --noEmit -p tsconfig.json && node ../../scripts/svelte-check-a11y.mjs --tsconfig ./tsconfig.svelte.json",
|
|
35
|
+
"verify:pack": "node ../../scripts/verify-package-types-exports.js ."
|
|
36
|
+
},
|
|
26
37
|
"dependencies": {
|
|
27
|
-
"@happyvertical/
|
|
28
|
-
"@happyvertical/smrt-
|
|
29
|
-
"@happyvertical/smrt-
|
|
30
|
-
"@happyvertical/smrt-
|
|
31
|
-
"@happyvertical/smrt-
|
|
32
|
-
"@happyvertical/smrt-
|
|
33
|
-
"@happyvertical/
|
|
38
|
+
"@happyvertical/smrt-agents": "workspace:*",
|
|
39
|
+
"@happyvertical/smrt-core": "workspace:*",
|
|
40
|
+
"@happyvertical/smrt-prompts": "workspace:*",
|
|
41
|
+
"@happyvertical/smrt-tenancy": "workspace:*",
|
|
42
|
+
"@happyvertical/smrt-ui": "workspace:*",
|
|
43
|
+
"@happyvertical/smrt-users": "workspace:*",
|
|
44
|
+
"@happyvertical/sql": "catalog:"
|
|
34
45
|
},
|
|
35
46
|
"peerDependencies": {
|
|
36
47
|
"svelte": "^5.56.4"
|
|
37
48
|
},
|
|
38
49
|
"devDependencies": {
|
|
50
|
+
"@happyvertical/smrt-vitest": "workspace:*",
|
|
39
51
|
"@sveltejs/package": "^2.5.8",
|
|
40
52
|
"@sveltejs/vite-plugin-svelte": "^7.1.2",
|
|
41
53
|
"@types/node": "24.13.2",
|
|
@@ -43,8 +55,7 @@
|
|
|
43
55
|
"svelte-check": "^4.7.1",
|
|
44
56
|
"typescript": "^5.9.3",
|
|
45
57
|
"vite": "^8.1.3",
|
|
46
|
-
"vitest": "^4.1.9"
|
|
47
|
-
"@happyvertical/smrt-vitest": "0.38.26"
|
|
58
|
+
"vitest": "^4.1.9"
|
|
48
59
|
},
|
|
49
60
|
"keywords": [
|
|
50
61
|
"smrt",
|
|
@@ -63,15 +74,5 @@
|
|
|
63
74
|
"type": "git",
|
|
64
75
|
"url": "https://github.com/happyvertical/smrt.git",
|
|
65
76
|
"directory": "packages/personas"
|
|
66
|
-
},
|
|
67
|
-
"scripts": {
|
|
68
|
-
"build": "vite build --mode library && svelte-package -i src/svelte -o dist/svelte --tsconfig tsconfig.svelte.json",
|
|
69
|
-
"build:watch": "vite build --mode library --watch",
|
|
70
|
-
"clean": "rm -rf dist",
|
|
71
|
-
"dev": "vite dev",
|
|
72
|
-
"test": "vitest run",
|
|
73
|
-
"test:watch": "vitest",
|
|
74
|
-
"typecheck": "tsc --noEmit -p tsconfig.json && node ../../scripts/svelte-check-a11y.mjs --tsconfig ./tsconfig.svelte.json",
|
|
75
|
-
"verify:pack": "node ../../scripts/verify-package-types-exports.js ."
|
|
76
77
|
}
|
|
77
|
-
}
|
|
78
|
+
}
|
package/LICENSE
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
Copyright <2025> <Happy Vertical Corporation>
|
|
2
|
-
|
|
3
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
-
|
|
5
|
-
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
-
|
|
7
|
-
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|