Implement the agent’s Logic
Now it’s time to write the core logic that makes your agent behave the way you want, using the SDK’s capabilities plus your integrated AI services. This includes designing prompts, handling user messages and tool invocations, and managing conversation state for multi-turn dialogues.
Design the System Prompt and Persona: Crafting a good system message (prompt) is crucial. This prompt defines the agent’s role, tone, and boundaries. For example:
• System prompt example: “You are TechHelpBot, an AI assistant for Contoso Corp’s IT helpdesk. You help employees troubleshoot technical issues and answer questions about IT policies. Be friendly and concise. If a request is outside of IT support, politely direct the user to the appropriate department. Use the knowledge base provided to give accurate answers. Do not disclose confidential info or any internal policies unless the user asks about them.” This prompt is fed to the model at conversation start and ensures the model responses stay in character.. In code, how you set this varies:
In Teams AI Library (JS), you might see something like planner.prompt.setSystemMessage("...") where you fill in the prompt.
In C#, you might use AgentOptions.DefaultPrompt or set up a prompt template with the content. If you have a prompt file (some projects use a .txt or .md file for system prompt), edit that file.
Also consider defining few-shot examples in the prompt.
Message Handling and Orchestration: The agent needs to decide how to respond to each user input. There are a few patterns:
Simple turn-by-turn with Learn Language Model (LLM): For many queries, you send the user’s message + system prompt (and relevant context) to the Learning Language Model and return its answer.. Ensure your code correctly captures the user message and calls OpenAI with the combined prompt.
Action/Tool usage: If you have functions (like the search tool, or say an “add calendar event” function), you need logic to decide when to call them. If using the Teams AI Action Planner, it can automatically parse the model’s intentions. For example, the planner might parse a user request “Schedule a team meeting tomorrow at 10” and realize an AddCalendarEvent action is needed. It calls your corresponding JS function, then incorporate the result (confirmation or details) into the final answer. In C#, without the Teams AI library, you might instead use a library like Semantic Kernel Planner or write if/else logic: For example, use regex or Azure CLU to detect “schedule meeting” intent, call an Outlook calendar API via Graph, then formulate a response.
Multi-step plans: The Agents SDK allows complex decision flows. Perhaps the user asks, “Find me the latest sales figures and draft an email to the team about it.” The agent might need to
(a) query a database or Power BI for sales figures,
(b) feed those into the Learning Language Model to generate a nicely worded email
(c) either send the email (requiring a Graph API call) or present it for user confirmation. Implementing these plans requires breaking down the tasks and possibly asking the model to do piecewise completions (or using a planner that can break it down, like Semantic Kernel’s planner or by chaining prompts). It’s advanced, but shows why a custom agent is powerful.
Use of Conversation History: By default, the model does not automatically get prior messages unless you include them in the prompt. Most bot frameworks maintain a conversation state or history. The Teams AI library, for instance, can keep a short transcript context of recent messages and pass it to the Learning Language Model so it has context. You should verify how your template handles history. Typically:
There’s a concept of a memory or state that stores recent turns. In a simple echo template, it might not store anything persistently (just in-memory while the bot is running).
For multi-turn Question & Answer, you might want to keep the last user question and answer when the user asks a follow-up. The Agents SDK supports connecting to persistent storage (Cosmos DB, Blob storage, etc.) for conversation state. If multi-turn context is important, set up the state manager to at least use memory storage initially (which may be the default).
Best practice is not to feed an ever-growing history to the model. Instead, use techniques like history summarization: after X turns, summarize the conversation so far and store that summary, then start a fresh context with the summary as background.
Implementing State and Memory: In C#, you might configure MemoryStorage or Cosmos DB in Startup. In JS, the Teams AI SDK might handle this behind scenes or let you plug in a storage provider. The point is to enable the agent to “remember” relevant info during a session, like the user’s name or preferences mentioned earlier, enabling more natural multi-turn interactions. According to the SDK docs, an agent by default is stateless across turns, so you need to use these storage mechanisms to maintain continuity.
Testing logic incrementally: As you implement the above, keep running the bot locally to test each piece. For example, test that the system prompt changes the bot’s tone. Test that when you ask for data, the search function is indeed called and its results are factored into the answer. Debugging printouts/logs are your friend here (log the prompt being sent to OpenAI, log any exceptions, etc.).
Example Walk-through
Let’s illustrate a simple flow – user asks: “What’s my next meeting?”
Without integration: The model alone can’t answer that (it doesn’t have user’s calendar).
With integration: You could integrate Microsoft Graph: detect the word “meeting” and call Graph for the user’s calendar. Then respond with details. In code, you might do:
if (userMessage.includes("my next meeting")) {
let events = await graphClient.getCalendarEvents(userId, /*top=1, filter= future*/);
if (events.length > 0) {
let next = events[0];
return `Your next meeting is "${next.subject}" on ${next.startTime}.`;
} else {
return "You have no upcoming meetings.";
}
}
This is a straightforward if/else approach embedded in the message handler. Alternatively, you could prompt the Learning Language Model: “User asks about next meeting. Here is their calendar: [data]. Answer accordingly.” But calling Graph via code is reliable.
This example underscores: for factual queries tied to user data, combine code and AI. Let the code handle data access (ensuring accuracy and permission), then perhaps let the Learning Language Model draft a nicely worded answer with that data. Iterate on the prompt and logic: Often you’ll need to refine the system prompt or add more examples if the model isn’t responding as desired. Also, tune your logic to handle edge cases. What if the search returns nothing? The agent should then say “Sorry, I couldn’t find info on that.” What if the user asks something the agent shouldn’t handle? The system prompt should guide refusal or safe response.
Your custom agent uses the Learning Language Model for free-form conversation, calls Azure services or APIs for specific tasks, and maintains context for multi-turn chats. You essentially program the “brain” of the agent: when to use AI vs. when to use deterministic code. This hybrid approach – your code + Learning Language Model – is what makes it a powerful custom agent.