Skip to content

Signum.Agent: AgentSkillEntity, runtime skill tree, headless loop#3

Open
olmobrutall wants to merge 24 commits intosync/signumsoftware-masterfrom
claude/check-repo-access-kohST
Open

Signum.Agent: AgentSkillEntity, runtime skill tree, headless loop#3
olmobrutall wants to merge 24 commits intosync/signumsoftware-masterfrom
claude/check-repo-access-kohST

Conversation

@olmobrutall
Copy link
Copy Markdown
Owner

Summary

  • AgentSkillEntity — DB-backed tree of skill instances. Each node has Name, SkillCode (links to a registered AgentSkillCode class), Active, UseCase (AgentUseCaseSymbol: DefaultChatbot / Summarizer), optional ShortDescription and Instructions overrides, PropertyOverrides (MList), and SubSkills (MList defining the hierarchy). The tree is now exclusively DB-driven; no deployment needed to change skill configuration.
  • AgentSkillCode — renamed from AgentSkill. Tree API removed. Registered via AgentSkillLogic.RegisterCode<T>().
  • AgentSkillPropertyAttribute / AgentSkillProperty_QueryListAttribute — marks overridable properties on skill code classes with custom ConvertFromString logic.
  • ResolvedSkillNode — runtime tree combining entity + code, built from DB and cached via GlobalLazy (invalidated on entity changes). Has GetInstruction, FindSkill, FindTool, GetTools*.
  • Circular reference validation on save via DirectedGraph.FeedbackEdgeSet (same pattern as RoleEntity).
  • IAgentOutput interface with no-op defaults; HttpAgentOutput implements it for streaming. The agent loop is extracted to ChatbotLogic.RunAgentLoopAsync and can run without an HTTP connection.
  • ChatbotLogic.RunHeadlessAsync — creates a session and runs the full agent loop headlessly (background jobs, tests, scheduled tasks).
  • API endpoints: /api/agentSkill/registeredCodes, skillCodeDefaults/{code}, skillCodeProperties/{code}.
  • AgentSkillClient.tsx — registry (registerPropertyValueControl(attributeName, factory)) for custom property value editors.
  • Templates/AgentSkill.tsx — entity template with MarkdownLine, LinkButton toggling between editor and DiffDocument (code default vs. DB override), dynamic property override controls, and sub-skills table.

Test plan

  • Register skill codes and verify GET /api/agentSkill/registeredCodes returns them
  • Create an AgentSkillEntity with UseCase = DefaultChatbot and verify chatbot uses its instructions
  • Override Instructions on an entity and confirm the diff view shows changes vs. code default
  • Add a circular sub-skill reference and verify save is rejected
  • Call ChatbotLogic.RunHeadlessAsync from a background context and verify it completes without HTTP

https://claude.ai/code/session_01DzaiFG2j85WBup5bdszYFb

JafarMirzaie and others added 24 commits April 2, 2026 12:13
- Rename AgentSkill → AgentSkillCode (pure code-side definition, no tree)
- Add AgentSkillEntity: DB-backed tree nodes with Name, SkillCode, Active,
  UseCase (AgentUseCaseSymbol), ShortDescription, Instructions overrides,
  PropertyOverrides (MList), and SubSkills (MList) defining the hierarchy
- Add AgentUseCaseSymbol with DefaultChatbot and Summarizer built-in values
- Add AgentSkillPropertyAttribute / AgentSkillProperty_QueryListAttribute
  for marking overridable skill properties with custom string converters
- Add ResolvedSkillNode: runtime combination of entity + code + sub-tree,
  built from DB and cached via GlobalLazy (invalidated on entity changes)
- Circular reference validation on save (DirectedGraph.FeedbackEdgeSet)
- AgentSkillLogic.RegisterCode<T>() replaces hard-coded tree API
- ChatbotController + ChatbotLogic updated to use ResolvedSkillNode via
  GetRootForUseCase(AgentUseCase.DefaultChatbot)
- CurrentMcpRoot thread variable for IntroductionSkill.Describe/ListSkillNames
- API endpoints: /api/agentSkill/registeredCodes, skillCodeDefaults, skillCodeProperties
- AgentSkillClient.tsx registry: registerPropertyValueControl(attributeName, factory)
- Templates/AgentSkill.tsx: MarkdownLine + LinkButton diff toggle vs code default,
  dynamic property value controls by attribute name, sub-skills table

https://claude.ai/code/session_01DzaiFG2j85WBup5bdszYFb
…xecution

- Add IAgentOutput interface with default no-op implementations for all events:
  OnSystemMessage, OnUserQuestion, OnSummarization, OnAssistantStarted,
  OnTextChunk, OnAssistantMessage, OnToolStart, OnToolFinished, OnTitleUpdated
- Add NullAgentOutput singleton (no-op implementation)
- Move agent loop (while-true LLM call + tool execution) from controller to
  ChatbotLogic.RunAgentLoopAsync(ConversationHistory, IAgentOutput, ct)
- Move ExecuteToolAsync and FormatToolError to ChatbotLogic (static)
- Add ChatbotLogic.RunHeadlessAsync(prompt, useCase, languageModel, output, ct)
  creates session, system msg, user msg and runs the loop without HTTP
- Add HttpAgentOutput class in controller implementing IAgentOutput via
  UINotification streaming writes to HttpResponse
- Simplify ChatbotController.AskQuestionAsync to HTTP setup + delegate to logic

https://claude.ai/code/session_01DzaiFG2j85WBup5bdszYFb
- AgentSkillCodeEntity is now a SystemString entity auto-synced from code
  via Schema_Generating/Schema_Synchronizing hooks (like EmailModelEntity)
- RegisterCode<T>() registers types only; instantiation via Activator.CreateInstance
- Merged SkillCodeDefaults+properties into single SkillCodeInfo response
- AgentSkillPropertyAttribute gains ValidateValue() called during entity save
- Removed ResolvedSkillNode: AgentSkillCode instances are built in-place at
  resolve time with SubSkills wired from DB entity tree
- ConversationHistory.RootSkill: ResolvedSkillNode -> AgentSkillCode
- Controller: replaced 3 endpoints with single /api/agentSkill/skillCodeInfo/{code}
- Frontend: EntityCombo for skillCode field, single getSkillCodeInfo API call,
  removed duplicate AgentSkillEntity settings registration from ChatbotClient

https://claude.ai/code/session_01DzaiFG2j85WBup5bdszYFb
IntroductionSkill is always the tree root, so Describe/ListSkillNames
can use 'this' directly instead of a thread-local variable.

https://claude.ai/code/session_01DzaiFG2j85WBup5bdszYFb
- LanguageModelLogic.cs: extracted from ChatbotLogic — entity setup for
  ChatbotLanguageModelEntity/EmbeddingsLanguageModelEntity, provider
  dictionaries, GetChatClient, ChatOptions, GetEmbeddingsAsync, lazy caches,
  IChatbotModelProvider/IEmbeddingsProvider interfaces
- LanguageModelController.cs: extracted GET models/embeddingModels endpoints
- All providers updated to call LanguageModelLogic.GetConfig()
- ChatbotLogic.Start now delegates to LanguageModelLogic.Start
- Removed all section-divider comments and XML doc blocks; kept only the
  UIToolAttribute summary and the SubSkills population hint

https://claude.ai/code/session_01DzaiFG2j85WBup5bdszYFb
- LanguageModelClient: start() registers ChatbotLanguageModel/EmbeddingsLanguageModel
  entity settings; API.getModels/getEmbeddingModels methods
- ChatbotClient: removed language model entity settings and model API methods;
  also removed the stale optiions typo and the UITool registry block comment
- Templates updated to import from LanguageModelClient instead of ChatbotClient

https://claude.ai/code/session_01DzaiFG2j85WBup5bdszYFb
…hST' into claude/check-repo-access-kohST

# Conflicts:
#	Extensions/Signum.Agent/ChatbotLogic.cs
These plain DTO interfaces are not generated by the T4 template so they
need to be declared manually in the .ts source file.

https://claude.ai/code/session_01DzaiFG2j85WBup5bdszYFb
Signum.Agent.ts is auto-generated and would overwrite manual additions.
Defining these plain DTO interfaces in AgentSkillClient.tsx instead;
template updated to import SkillPropertyMeta from there.
Also removed them from Signum.Agent.d.ts (derived file).

https://claude.ai/code/session_01DzaiFG2j85WBup5bdszYFb
Framework is used as a submodule; the parent project manages the lockfile.

https://claude.ai/code/session_01DzaiFG2j85WBup5bdszYFb
Without this, TypeScript silently falls back to including source files
from referenced projects when their ts_out hasn't been built, generating
stray .d.ts/.d.ts.map files in the wrong project's output directory.
With this flag, TypeScript errors immediately instead, making missing
project references obvious.

https://claude.ai/code/session_01DzaiFG2j85WBup5bdszYFb
IAgentOutput:
- Remove default implementations; move them all to NullAgentOutput

AgentSkillSubSkillEmbedded.Skill:
- Changed from Lite<AgentSkillEntity> to [ImplementedBy] Lite<Entity>
  so a sub-skill can be an AgentSkillEntity (customised) or an
  AgentSkillCodeEntity (default, no DB entity required)

DefaultRoots registry:
- AgentSkillLogic.RegisterDefaultRoot(useCase, factory) registers a
  Func<AgentSkillCode> used as fallback when no DB entity exists for
  that use case, and as the source for ConstructFromUseCase
- RootsByUseCase falls back to factory if no active entity found in DB

AgentSkillOperation.CreateFromUseCase:
- ConstructFrom<AgentUseCaseSymbol>: calls the registered factory,
  converts the code tree to AgentSkillEntity/AgentSkillCodeEntity
  references (NeedsEntity decides per node), saves child entities

AgentSkillPropertyAttribute.ConvertValueToString:
- Reverse of ConvertFromString; used by NeedsEntity to detect
  non-default property values when converting a factory tree to DB

AgentSkillCode.WithSubSkill():
- Fluent builder for constructing default trees in factory functions

https://claude.ai/code/session_01DzaiFG2j85WBup5bdszYFb
IsDefault() checks no sub-skills, no instructions/description overrides, and no
property overrides — the entity-side equivalent of NeedsEntity(). NeedsEntity now
compares OriginalInstructions directly instead of using the removed HasCustomInstructions flag.

https://claude.ai/code/session_01DzaiFG2j85WBup5bdszYFb
AgentSkillCode.IsDefault() checks no sub-skills, unmodified short description,
unmodified instructions, and all [AgentSkillProperty] values at their defaults.
NeedsEntity() becomes a one-liner: !code.IsDefault().

https://claude.ai/code/session_01DzaiFG2j85WBup5bdszYFb
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants