Langcore Extension Cog Integration Guide¶
Required Steps¶
- Listen for
on_langcore_cog_addand receive the langcore cog instance. - Register tool schemas with
langcore_cog.hub.register_function(...). - Register a cog-specific system prompt via
langcore_cog.conversation_manager.register_cog_system_prompt(...). - (Optional) Register a
MessageHandlerfor rich responses withlangcore_cog.register_message_handler(...). - (Optional) Use a sub-agent (see
SubAgentbelow) when your cog orchestrates its own tool loop.
Tool Signature Contract¶
- Tool callbacks must accept
ctx: ExtensionContextas the final parameter. The langcore wrapper injects it automatically. - Backward compatibility: if your signature does not accept
ctx, the wrapper falls back to the oldguild_id/channel_id/member_idkwargs and finally to raw tool args.
from langcore.abc import ExtensionContext
async def my_tool(user_query: str, ctx: ExtensionContext) -> str:
provider = ctx.get_provider()
store = ctx.get_store()
await ctx.add_to_conversation("Working on it...")
# ... do work ...
return "✅ Done"
ExtensionContext API¶
- Fields:
guild_id,channel_id,member_id,langcore,default_provider(optional). ctx.get_provider(name=None): returns the requested provider or the guild default (see below).ctx.get_store(): returns the configuredChainStore, raising if missing.await ctx.add_to_conversation(content, role="assistant", tool_call_id=None, name=None): thread-safe injection into the conversation using langcore's locking helper.
Provider Selection¶
- Guilds configure a preferred provider via
[p]langcore defaultprovider <name>. ctx.get_provider()uses the configured default whennameis omitted, falling back tolangcore.DEFAULT_PROVIDER_FALLBACK.await langcore_cog.get_default_provider(guild_id)is available when you need the provider outside of a tool callback.
Sub-Agent Pattern¶
- Use
langcore.abc.SubAgentfor reusable tool-calling loops. - Example skeleton:
class MyManager(SubAgent): async def handle_request(self, request: str, ctx: ExtensionContext) -> str: messages = [ {"role": "system", "content": "..."}, {"role": "user", "content": request}, ] callbacks = {"search": self.search} return await self.run_tool_loop( messages=messages, tools=[{"name": "search"}], callbacks=callbacks, guild_id=ctx.guild_id, channel_id=ctx.channel_id, member_id=ctx.member_id, provider=ctx.get_provider(), )
Lazy Loading & No Imports¶
- Do not hard-import
langcoremodules inside extension/provider/store cogs. Prefer dynamic imports (e.g.,import_module("langcore.abc")) or event-driven registration viaon_langcore_cog_add/on_langcore_cog_remove. - Tool signatures can accept
ctx: Any = None; callgetattr(ctx, "get_provider", lambda: None)()andgetattr(ctx, "add_to_conversation", None)defensively so the cog can load without langcore. - Standalone features (like
[p]mermaid) must function when langcore is absent. - Provider/store cogs should mirror the lazy pattern from ollama/openrouter/qdrant: build ABC subclasses dynamically and register only after receiving the langcore add event.
- If langcore isn’t present, return a clear error from tool callbacks instead of failing at import time.
Migration Checklist (old pattern → new pattern)¶
- Replace
langcore_cog.get_provider("ollama")withctx.get_provider(). - Replace manual lock handling and
conversation.add_*calls withawait ctx.add_to_conversation(...)orlangcore_cog.inject_conversation_content(...). - Pass
ctxthrough to managers and helpers instead of raw IDs. - Avoid direct
conversation_manageraccess unless absolutely needed; rely on the injected helpers. - Use
[p]langcore defaultprovider <name>to keep provider selection configurable per guild.
Troubleshooting¶
- Missing ctx: ensure your tool signature includes
ctx: ExtensionContext; the wrapper logs a debug message when it falls back. - Provider not registered: load the provider cog and/or update the default with
[p]langcore defaultprovider. - Conversation injection errors: confirm langcore is loaded and the conversation exists;
ctx.add_to_conversationhandles locking but will surface errors if the conversation cannot be found. - Tool args dropped: if a callback rejects injected kwargs, the wrapper retries with legacy parameters, then raw args. Check debug logs for the rejection details.
See langcore/ARCHITECTURE.md for architecture diagrams and deeper background.