Level 3 — Lesson 1 of 5 — Structure your Agent Studio code so it stays manageable as your project grows.
How Agent Studio organises code
Each entry on the Functions page is a Python file, not just a single function. This means you can define multiple functions in one file — utility helpers, validation logic, formatters — alongside the main function that Agent Studio creates.- Each file has one main function with the same name as the file — this is the one Agent Studio validates and constrains (it must accept
convas the first argument) - You can define additional functions above the main function — these are helpers that don’t need to follow Agent Studio’s signature rules
- Flow functions live in a subfolder named after the flow
Utility files
You don’t need 50 separate function entries for 50 helpers. Group related utilities in a single file:Importing functions
There are two ways to use code from other files.Method 1: Python imports
Standard Python import syntax works for any function in any file:conv (and flow for flow functions) as arguments:
Method 2: conv.functions and flow.functions
The platform-supported method for calling main functions:
- Autocomplete and type hints in the editor
- No need to pass
convorflow— they’re handled automatically - Officially supported by the platform
is_valid_tracking_number) through conv.functions.
When to use which method
| Scenario | Method |
|---|---|
| Calling a main function from another file | conv.functions.functionName() |
| Calling a utility/helper from a utils file | from functions.fileName import helperName |
| Calling a flow function from outside the flow | flow.functions.functionName() |
| Need autocomplete and type hints | conv.functions / flow.functions |
Practical example: order tracking
Here’s how a real flow function uses both import methods:Function types and their roles
As your project grows, distinguishing between different function types becomes critical. Here’s a reference for how to think about each type:| Function type | LLM-callable? | Description |
|---|---|---|
| Flow functions | Yes | Local to a single flow. Keep them thin — they orchestrate step logic and delegate complex work to global functions. |
| Global functions (KB / general-purpose) | Yes | Reusable across flows and KB topics. Includes flow start functions, transfer calls, and other shared callable functions. |
| API handlers | No | Handle outbound calls to external services. Never call directly from prompts. |
| Services | No | Business rules and orchestration between APIs, models, and utilities. |
| Utility files | No | Simple, deterministic helpers (string formatting, date conversion). No side effects. |
| Constants | No | Shared constants, enums, and configuration values. No logic. |
Separation of concerns
Follow a “thin flows, fat services” approach:- Keep LLM-facing flow functions focused on: collecting user input, writing state, and transitioning steps
- Put deterministic logic (validation, comparisons, branching rules, API formatting) in helper modules
- Do not import LLM-facing functions into unrelated helpers as a way to reuse business logic — reuse helper functions instead
Best practices
Group related helpers
Don’t create one function entry per helper. Group formatting utils, validation utils, and API utils into their own files.
Define once, use everywhere
If a regex pattern or validation rule is needed in multiple places, define it in a utility file and import it. Update once, fix everywhere.
Use conv.functions where possible
For main functions, prefer the platform-supported
conv.functions method. Reserve Python imports for utility helpers.Keep functions focused
Each main function should do one thing. Complex logic should be broken into helpers that are composed together.
Common pitfalls
| Pitfall | Solution |
|---|---|
| Business logic embedded in flow functions | Move to global services or utils. Keep flow functions focused on orchestration. |
| ”Invisible functions” that can’t be found | Use clear naming. Centralise reusable logic in global functions. Never import logic from flow functions into others. |
| Duplicated logic across functions | Centralise repeated patterns into a single global function or util. Update in one place. |
| Bloated global function files | Simulate folders by namespacing files by concern (e.g., tracking_utils, tracking_api, tracking_service). |
| Circular dependencies | Follow the function hierarchy: flow functions → global functions → services → utils. Never import upward. |
Try it yourself
Challenge: Refactor a monolithic function
You have a single function that validates a tracking number, calls an API, formats the result for TTS, and returns it. It’s 80 lines long.Plan how you would split this into:
- A validation utility
- An API wrapper
- A TTS formatting utility
- A main function that composes them
Hint
Hint
Create a
trackingUtils.py with the validation and formatting helpers. Create a getOrder.py for the API call. The main flow function imports from both and orchestrates the logic.Example structure
Example structure
trackingUtils.py:
is_valid_tracking_number(number)— regex validationtracking_number_to_words(number)— TTS formattingtracking_utils(conv)— no-op main function
getOrder(conv, tracking_number)— API call, returns order dict or None
← Back to PolyAcademy
Level overview
Next: Flow fundamentals →
Lesson 2 of 5

