0 Followers · 214 Posts

A programming tool or software development tool is a computer program that software developers use to create, debug, maintain, or otherwise support other programs and applications.

Question Pietro Di Leo · Jan 17, 2024

Hi everyone, 

Does anyone know how to export projects via VSC? 

I opened the project through the "InterSystems Tools" plugin (command is "Edit Code in Project") and I can correctly work on it.

However, when I try using the "ObjectScript" plugin to export the project (right click on the project -> "Export Project Contents")

This message appears and it is not possible to export the project:

I've tried also to open a new window, then a folder and finally the project, but nothing changes. 

This is an example of my workspace: 


Anyone knows how to do it? 

Thank you! 

6
0 2978
Discussion Yone Moreno Jiménez · Aug 1, 2025

Hello InterSystems Community,

I hope you're all doing well. I'm reaching out to ask if there's any way to enable a dark theme or dark mode for the HealthShare Management Portal.

Background

I have a visual impairment (amblyopia/lazy eye) which means I'm nearly blind in one eye. Like many people with visual difficulties, I find that bright white backgrounds and interfaces cause significant eye strain and fatigue. This makes it challenging to work with the Management Portal for extended periods.

What I've Found So Far

8
0 171
Article Sanjib Pandey · Oct 17, 2025 13m read

Overview

This web interface is designed to facilitate the management of Data Lookup Tables via a user-friendly web page. It is particularly useful when your lookup table values are large, dynamic, and frequently changing. By granting end-users controlled access to this web interface (read, write, and delete permissions limited to this page), they can efficiently manage lookup table data according to their needs.

The data managed through this interface can be seamlessly utilized in HealthConnect rules or data transformations, eliminating the need for constant manual monitoring and management of the lookup tables and thereby saving significant time.

Note:
If the standard Data Lookup Table does not meet your mapping requirements, you can create a custom table and adapt this web interface along with its supporting class with minimal modifications. Sample class code is available upon request.

0
1 59
Article Pietro Di Leo · Nov 16, 2023 5m read

Introduction

Since InterSystems has recently announced the discontinuation of support for InterSystems Studio starting from version 2023.2 in favor of exclusive development of extensions for the Visual Studio Code (VSC) IDE, believing that the latter offers a superior experience compared to Studio, many of us developers have switched or are beginning to use VSC. Many may have wondered how to open the Terminal to perform operations, as VSC does not have an Output panel like Studio did, nor an integrated feature to open the IRIS terminal, except by downloading the plugins developed by InterSystems.

10
12 2222
Article Pietro Di Leo · Oct 6, 2025 4m read
2
0 73
Article Pietro Di Leo · Oct 6, 2025 5m read

Hi everyone! 👋
I’m excited to share the project I’ve submitted to the current InterSystems .Net, Java, Python, and JavaScript Contest — it’s called IRIStool and Data Manager, and you can find it on the InterSystems Open Exchange and on my GitHub page.

1
2 67
Announcement Kimi Niittyniemi · Sep 14, 2025

We are excited to announce the general availability of JediSoft IRISsync®, our new synchronization and comparison solution built on InterSystems IRIS technology.  IRISsync makes it easy to synchronize and compare IRIS instances.

IRISsync was voted runner-up in the "Most Likely to Use" category at InterSystems READY 2025 Demos and Drinks.

A huge thanks to everyone who supported us — we’re thrilled to see IRISsync resonating with the InterSystems user community!

0
0 74
Article John Murray · Dec 18, 2024 1m read

A benefit of using Doxygenerate is that Doxygen does more than just HTML output. Tweak the Doxyfile that tells Doxygen what to do and you can easily create a PDF. Our example MARINA application yielded a 524-page PDF. Here's what page 94 looks like:

You can browse the whole file here.

In the screenshot above, notice how we only get details of the superclass that is part of the app (AuditHistory). The primary superclass, %Library.SerialObject, is shown faded and with no details of what BankDetails inherits from it.

1
1 275
Article Victoria Castillo · Mar 19, 2024 5m read

I have been walking through this with a few team members and as such I thought there might be others out there who could use it, especially if you work with HL7 & Ensemble/HealthConnect/HealthShare and never venture out past the Interoperability section. 

First, I would like to establish that this is an extension of the already established documentation on importing and exporting SQL data found here: https://docs.intersystems.com/iris20241/csp/docbook/DocBook.UI.Page.cls?KEY=GSQL_impexp#GSQL_impexp_import

2
1 666
Article Robert Barbiaux · Sep 1, 2025 9m read

InterSystems IRIS interoperability production development involves using or writing various types of components. They include services (which handle incoming data), processes (which deal with the data flow and logic), and operations (which manage outgoing data or requests). Messages flowing through those components constantly require being adapted to consuming applications. Therefore,Data transformations are by far the most common component in interoperability productions.

0
0 91
Article Alberto Fuentes · Sep 1, 2025 7m read

Customer support questions span structured data (orders, products 🗃️), unstructured knowledge (docs/FAQs 📚), and live systems (shipping updates 🚚). In this post we’ll ship a compact AI agent that handles all three—using:

  • 🧠 Python + smolagents to orchestrate the agent’s “brain”
  • 🧰 InterSystems IRIS for SQL, Vector Search (RAG), and Interoperability (a mock shipping status API)

⚡ TL;DR (snack-sized)

  • Build a working AI Customer Support Agent with Python + smolagents orchestrating tools on InterSystems IRIS (SQL, Vector Search/RAG, Interoperability for a mock shipping API).
  • It answers real questions (e.g., “Was order #1001 delivered?”“What’s the return window?”) by combining tables, documents, and interoperability calls.
  • You’ll spin up IRIS in Docker, load schema and sample data, embed docs for RAG, register tools (SQL/RAG/API), and run the agent via CLI or Gradio UI.

image


🧭 What you’ll build

An AI Customer Support Agent that can:

  • 🔎 Query structured data (customers, orders, products, shipments) via SQL
  • 📚 Retrieve unstructured knowledge (FAQs & docs) via RAG on IRIS Vector Search
  • 🔌 Call a (mock) shipping API via IRIS Interoperability, with Visual Trace to inspect every call

Architecture (at a glance)

User ➜ Agent (smolagents CodeAgent)
               ├─ SQL Tool ➜ IRIS tables
               ├─ RAG Tool ➜ IRIS Vector Search (embeddings + chunks)
               └─ Shipping Tool ➜ IRIS Interoperability (mock shipping) ➜ Visual Trace

New to smolagents? It’s a tiny agent framework from Hugging Face where the model plans and uses your tools—other alternatives are LangGraph and LlamaIndex.


🧱 Prerequisites

  • 🐍 Python 3.9+
  • 🐳 Docker to run IRIS in a container
  • 🧑‍💻 VS Code handy to checkout the code
  • 🔑 OpenAI API key for the LLM + embeddings — or run locally with Ollama if you prefer

1) 🧩 Clone & set up Python

git clone https://github.com/intersystems-ib/customer-support-agent-demo
cd customer-support-agent-demo

python -m venv .venv
# macOS/Linux
source .venv/bin/activate
# Windows (PowerShell)
# .venv\Scripts\Activate.ps1

pip install -r requirements.txt
cp .env.example .env   # add your OpenAI key

2) 🐳 Start InterSystems IRIS (Docker)

docker compose build
docker compose up -d

Open the Management Portal (http://localhost:52773 in this demo).


3) 🗃️ Load the structured data (SQL)

From SQL Explorer (Portal) or your favorite SQL client:

LOAD SQL FROM FILE '/app/iris/sql/schema.sql' DIALECT 'IRIS' DELIMITER ';';
LOAD SQL FROM FILE '/app/iris/sql/load_data.sql' DIALECT 'IRIS' DELIMITER ';';

This is the schema you have just loaded: image

Run some queries and get familiar with the data. The agent will use this data to resolve questions:

-- List customers
SELECT * FROM Agent_Data.Customers;

-- Orders for a given customer
SELECT o.OrderID, o.OrderDate, o.Status, p.Name AS Product
FROM Agent_Data.Orders o
JOIN Agent_Data.Products p ON o.ProductID = p.ProductID
WHERE o.CustomerID = 1;

-- Shipment info for an order
SELECT * FROM Agent_Data.Shipments WHERE OrderID = 1001;

✅ If you see rows, your structured side is ready.


4) 📚 Add unstructured knowledge with Vector Search (RAG)

Create an embedding config (example below uses an OpenAI embedding model—tweak to taste):

INSERT INTO %Embedding.Config
  (Name, Configuration, EmbeddingClass, VectorLength, Description)
VALUES
  ('my-openai-config',
   '{"apiKey":"YOUR_OPENAI_KEY","sslConfig":"llm_ssl","modelName":"text-embedding-3-small"}',
   '%Embedding.OpenAI',
   1536,
   'a small embedding model provided by OpenAI');

Need the exact steps and options? Check the documentation

Then embed the sample content:

python scripts/embed_sql.py

Check the embeddings are already in the tables:

SELECT COUNT(*) AS ProductChunks FROM Agent_Data.Products;
SELECT COUNT(*) AS DocChunks     FROM Agent_Data.DocChunks;

🔎 Bonus: Hybrid + vector search directly from SQL with EMBEDDING()

A major advantage of IRIS is that you can perform semantic (vector) search right inside SQL and mix it with classic filters—no extra microservices needed. The EMBEDDING() SQL function generates a vector on the fly for your query text, which you can compare against stored vectors using operations like VECTOR_DOT_PRODUCT.

Example A — Hybrid product search (price filter + semantic ranking):

SELECT TOP 3
    p.ProductID,
    p.Name,
    p.Category,
    p.Price,
    VECTOR_DOT_PRODUCT(p.Embedding, EMBEDDING('headphones with ANC', 'my-openai-config')) score
FROM Agent_Data.Products p
WHERE p.Price < 200
ORDER BY score DESC

Example B — Semantic doc-chunk lookup (great for feeding RAG answers):

SELECT TOP 3
    c.ChunkID  AS chunk_id,
    c.DocID      AS doc_id,
    c.Title         AS title,
    SUBSTRING(c.ChunkText, 1, 400) AS snippet,
    VECTOR_DOT_PRODUCT(c.Embedding, EMBEDDING('warranty coverage', 'my-openai-config')) AS score
FROM Agent_Data.DocChunks c
ORDER BY score DESC

Why this is powerful: you can pre-filter by price, category, language, tenant, dates, etc., and then rank by semantic similarity—all in one SQL statement.


5) 🔌 Wire a live (mock) shipping API with Interoperability

The project exposes a tiny /api/shipping/status endpoint through IRIS Interoperability—perfect to simulate “real world” calls:

curl -H "Content-Type: application/json" \
  -X POST \
  -d '{"orderStatus":"Processing","trackingNumber":"DHL7788"}' \
  http://localhost:52773/api/shipping/status

Now open Visual Trace in the Portal to watch the message flow hop-by-hop (it’s like airport radar for your integration ✈️).


6) 🤖 Meet the agent (smolagents + tools)

Peek at these files:

  • agent/customer_support_agent.py — boots a CodeAgent and registers tools
  • agent/tools/sql_tool.py — parameterized SQL helpers
  • agent/tools/rag_tool.py — vector search + doc retrieval
  • agent/tools/shipping_tool.py — calls the Interoperability endpoint

The CodeAgent plans with short code steps and calls your tools. You bring the tools; it brings the brains using a LLM model


7) ▶️ Run it!

One-shot (quick tests)

python -m cli.run --email alice@example.com --message "Where is my order #1001?"
python -m cli.run --email alice@example.com --message "Show electronics that are good for travel"
python -m cli.run --email alice@example.com --message "Was my headphones order delivered, and what’s the return window?"

Interactive CLI

python -m cli.run --email alice@example.com

Web UI (Gradio)

python -m ui.gradio
# open http://localhost:7860

🛠️ Under the hood

The agent’s flow (simplified):

  1. 🧭 Plan how to resolve the question and what available tools must be used: e.g., “check order status → fetch returns policy ”.

  2. 🛤️ Call tools as needed

    • 🗃️ SQL for customers/orders/products
    • 📚 RAG over embeddings for FAQs/docs (and remember, you can prototype RAG right inside SQL using EMBEDDING() + vector ops as shown above)
    • 🔌 Interoperability API for shipping status
  3. 🧩 Synthesize: stitch results into a friendly, precise answer.

Add or swap tools as your use case grows: promotions, warranties, inventory, you name it.


🎁 Wrap-up

You now have a compact AI Customer Support Agent that blends:

  • 🧠 LLM reasoning (smolagents CodeAgent)
  • 🗃️ Structured data (IRIS SQL)
  • 📚 Unstructured knowledge (IRIS Vector Search + RAG) — with the bonus that EMBEDDING() lets you do hybrid + vector search directly from SQL
  • 🔌 Live system calls (IRIS Interoperability + Visual Trace)
0
1 101
Announcement David McCaldon · Aug 18, 2025

I’m pleased to announce the release of tree-sitter-objectscript, a new open-source tree-sitter grammar that brings first-class ObjectScript support to modern editors. If you caught the preview at READY ’25, you’ll be glad to know it’s now up on Github:

https://github.com/intersystems/tree-sitter-objectscript

What Does It Provide?

  • Fast & Precise Parsing: A powerful grammar for ObjectScript, enabling real-time syntax parsing, smart highlighting, and structural editing in modern code editors.
  • Polyglot-Awareness: ObjectScript .cls files often embed SQL, HTML, Python, JavaScript, JSON, CSS, XML, and Markdown. The grammar is designed to integrate with those seamlessly.
  • Multi-Editor Support: Works across multiple editors today, with others coming as tree-sitter adoption grows.

Supported Editors

We've been working with tree-sitter-objectscript and the following editors:

Screenshot (Zed)

Screenshot of syntax highlighting in Zed

(this is actually Zed on Windows with a Tokyo Night Storm theme).


We’re excited to see how the community uses this — feedback and ideas are always welcome!

Thanks!

12
4 300
Article Pietro Di Leo · Aug 21, 2025 3m read

Recently, I replaced my old laptop with a new one and had to migrate all my data. I was looking for a guide but couldn’t find anything that explained in detail how to migrate server connections from InterSystems Studio and Visual Studio Code from one PC to another. Simply reinstalling the tools is not enough, and migrating all the connections manually seemed like a waste of time. In the end, I managed to solve the problem, and this article explains how.

InterSystems Studio

Exporting Server Connections

0
2 103
Question Andre Ribera · Mar 25, 2025

Been testing out the Production Validator toolkit, just to see what we can/not do with it. Seems really interesting and there seem to be some use cases for it that can really streamline some upgrades (or at least parts of upgrades) but I was running into so many hurdles with the documentation. I am curious if anyone else has used it.
Did you experience any issues getting it working? Any clarification that you would have liked in the documentation? any use cases that you worked through that made it particularly valuable? etc?
The hurdles I experienced included:

6
0 159
Article Yuri Marx · Jul 26, 2025 8m read

Word documents are widely used in the market. Users frequently create contracts, memos, resumes, reports, analyses, and other documents that may require data from or captured by InterSystems IRIS. However, IRIS does not have an API, SDK, library, or adapter for this. This limitation no longer exists. 

The new Open Exchange library iris4word (https://openexchange.intersystems.com/package/iris4word) delivers an ObjectScript SDK where the developer passes any %DynamicObject as a parameter, a Word file template and then receives a ready document, with the structure and formatting defined in its template.


2
3 90
Article Guillaume Rongier · Jul 28, 2025 6m read

img

Now that we have a good understanding of Python and its features, let's explore how we can leverage Python within IRIS.

Language Tag

The language tag is a feature of IRIS that allows you to write Python code directly in your ObjectScript classes.

This is useful for quick prototyping or when you want to use Python's features without creating a separate Python script.

How to use it?

To use the language tag, you need to define a class method with the Language = python attribute. Here's an example:

Class Article.LanguageTagExample Extends %RegisteredObject
{

ClassMethod Run() [ Language = python ]
{
        import requests

        response = requests.get("https://2eb86668f7ab407989787c97ec6b24ba.api.mockbin.io/")

        my_dict = response.json()

        for key, value in my_dict.items():
            print(f"{key}: {value}") # print message: Hello World
}

}

So what are the pros and cons of using the language tag?

Pros

  • Simplicity: You can write Python code directly in your ObjectScript classes without needing to create separate Python files.
  • Quick Prototyping: It's great for quick prototyping or testing small pieces of Python code.
  • Integration: You can easily integrate Python code with your ObjectScript code

Cons

  • Mixed Code: Mixing Python and ObjectScript code can make your code harder to read and maintain.
  • Debugging: You can't remotely debug Python code written in the language tag, which can be a limitation for complex applications.
  • Tracebacks: Python tracebacks are not displayed, you only see an ObjectScript error message, which can make debugging more difficult.

Conclusion

The language tag is a powerful feature that allows you to write Python code directly in your ObjectScript classes. However, it has its limitations, and it's important to use it wisely. For larger projects or when you need to debug your Python code, it's better to create separate Python scripts and import them into your ObjectScript classes.

Importing Python Modules (pypi modules)

Now that we have a good understanding of the language tag, let's explore how to import Python modules and use them in ObjectScript.

First, we will do it only with the built-in and third-party modules that come from PyPI, like requests, numpy, etc.

How to use it

So here, we will do the same thing, but using only the requests module from PyPI.

Class Article.RequestsExample Extends %RegisteredObject
{

ClassMethod Run() As %Status
{
    set builtins = ##class(%SYS.Python).Import("builtins")
    Set requests = ##class(%SYS.Python).Import("requests")

    Set response = requests.get("https://2eb86668f7ab407989787c97ec6b24ba.api.mockbin.io/")
    Set myDict = response.json()

    for i=0:1:builtins.len(myDict)-1 {
        set key = builtins.list(myDict.keys())."__getitem__"(i)
        set value = builtins.list(myDict.values())."__getitem__"(i)
        write key, ": ", value, !
    }
}

}

Let's run it:

iris session iris -U IRISAPP '##class(Article.RequestsExample).Run()'

You will see the output:

message: Hello World

Pros

  • Access to Python Libraries: You can use any Python library available on PyPI, which gives you access to a vast ecosystem of libraries and tools.
  • One type of code: You are only writing ObjectScript code, which makes it easier to read and maintain.
  • Debugging: You can debug your ObjectScript as it was only ObjectScript code, which it is :)

Cons

  • Good knowledge of Python: You need to have a good understanding of Python to use its libraries effectively.
  • Not writing Python code: You are not writing Python code, but ObjectScript code that calls Python code, which avoids the sugar syntax of Python.

Conclusion

In conclusion, importing Python modules into ObjectScript can greatly enhance your application's capabilities by leveraging the vast ecosystem of Python libraries. However, it's essential to understand the trade-offs involved, such as the need for a solid grasp of Python.

Importing Python Modules (custom modules)

Let's keep going with the same example, but this time we will create a custom Python module and import it into ObjectScript.

This time, we will be using python as much as possible, and we will only use ObjectScript to call the Python code.

How to use it

Let's create a custom Python module named my_script.py with the following content:

import requests

def run():
    response = requests.get("https://2eb86668f7ab407989787c97ec6b24ba.api.mockbin.io/")

    my_dict = response.json()

    for key, value in my_dict.items():
        print(f"{key}: {value}") # print message: Hello World

Now, we will create an ObjectScript class to import and run this Python module:

Class Article.MyScriptExample Extends %RegisteredObject
{
    ClassMethod Run() As %Status
    {
        set sys = ##class(%SYS.Python).Import("sys")
        do sys.path.append("/irisdev/app/src/python/article")  // Adjust the path to your module

        Set myScript = ##class(%SYS.Python).Import("my_script")

        Do myScript.run()

        Quit $$$OK
    }
}

Now, let's run it:

iris session iris -U IRISAPP '##class(Article.MyScriptExample).Run()'

⚠️ Don't forget to change your iris session to make sure you are on the last version of the code, see the first article for more details.

You will see the output:

message: Hello World

This demonstrates how to import a custom Python module into ObjectScript and execute its code.

Pros

  • Modularity: You can organize your Python code into modules, making it easier to manage and maintain.
  • Python Syntax: You can write Python code with its syntax and features
  • Debugging: Not of the box today, but in the next article, we will see how to debug Python code in IRIS.

Cons

  • Path Management: You need to manage the path to your Python module, see the article about sys.path for more details.
  • Python Knowledge: You still need to have a good understanding of Python to write and maintain your modules.
  • ObjectScript Knowledge: You need to know how to use ObjectScript to import and call your Python modules.

Conclusion

In conclusion, importing Python modules into ObjectScript can greatly enhance your application's capabilities by leveraging the vast ecosystem of Python libraries. However, it's essential to understand the trade-offs involved, such as the need for a solid grasp of Python.

2
4 153
Announcement Evgeny Shvarov · Jul 14, 2025

Here are the technology bonuses for the InterSystems Developer Tools Contest 2025 that will give you extra points in the voting:

  • IRIS Vector Search usage -3
  • Embedded Python usage -3
  • InterSystems Interoperability - 3
  • InterSystems IRIS BI - 3
  • VSCode Plugin - 3
  • FHIR Tools - 3
  • Docker container usage -2 
  • ZPM Package Deployment - 2
  • Implement InterSystems Community Idea - 4
  • Find a bug in Embedded Python - 2
  • Article on Developer Community - 2
  • The second article on Developer Community - 1
  • Video on YouTube - 3
  • First Time Contribution - 3

See the details below.<--break->

3
0 125
Announcement John Murray · Jul 23, 2025

Users of the %UnitTest framework can now get test coverage information inside VS Code by combining the latest release (v2.0.0) of the InterSystems Testing Manager extension with @Timothy Leavitt's impressive Test Coverage Tool.

Above you can see the Test Coverage pane, which I have moved to the secondary sidebar on the right so it can more easily be explored in conjunction with the Test Explorer on the left.

0
0 80
Article Sylvain Guilbaud · Jul 18, 2025 8m read

🛠️ Managing InterSystems InterSystems API Manager (IAM = Kong Gateway) configurations in CI/CD

🔍 Context: InterSystems IAM configurations 

As part of integrating InterSystems IRIS into a secure and controlled environment, InterSystems IAM relies on Kong Gateway to manage exposed APIs.
Kong acts as a modern API Gateway, capable of handling authentication, security, traffic management, plugins, and more.

0
1 61
Article Henry Pereira · Jun 11, 2025 15m read

Learn how to design scalable, autonomous AI agents that combine reasoning, vector search, and tool integration using LangGraph.

cover

Too Long; Didn't Read

  • AI Agents are proactive systems that combine memory, context, and initiative to automate tasks beyond simple chatbots.
  • LangGraph is a framework that enables us to build complex AI workflows, utilizing nodes (tasks) and edges (connections) with built-in state management.
  • This guide will walk you through building an AI-powered customer support agent that classifies priorities, identifies relevant topics, and determines whether to escalate or auto-reply.

So, What Exactly Are AI Agents?

Let’s face it — “AI agents” can sound like the robots that will take over your boardroom. In reality, they are your proactive sidekicks that can streamline complex workflows and eliminate repetitive tasks. Think of them as the next evolutionary step beyond chatbots: they do not just simply wait for prompts; they initiate actions, coordinate multiple steps, and adapt as they go.

Back in the day, crafting a “smart” system meant juggling separate models for language understanding, code generation, data lookup, you name it, and then duct-taping them together. Half of your time used to vanish in integration hell, whereas the other half you spent debugging the glue.

Agents flip that script. They bundle context, initiative, and adaptability into a single orchestrated flow. It is not just automation; it is intelligence with a mission. And thanks to such frameworks as LangGraph, assembling an agent squad of your own can actually be… dare I say, fun?

image

What Is LangGraph, Exactly?

LangGraph is an innovative framework that revolutionizes the way we build complex applications involving Large Language Models (LLMs).

Imagine that you are conducting an orchestra: every instrument (or “node”) needs to know when to play, how loud, and in what sequence. LangGraph, in this case**,** is your baton, giving you the following:

  • Graph Structure: It employs a graph-like structure with nodes and edges, enabling developers to design flexible, non-linear workflows that accommodate branches and loops. It mirrors complex decision-making processes resembling the way neural pathways might work.
  • State Management: LangGraph offers built-in tools for state persistence and error recovery, simplifying the maintenance of contextual data across various stages within an application. It can effectively switch between short-term and long-term memory, enhancing interaction quality thanks to such tools as Zep.
  • Tool Integration: With LangGraph, LLM agents can easily collaborate with external services or databases to fetch real-world data, improving the functionality and responsiveness of your applications.
  • Human-in-the-Loop: Beyond automation, LangGraph accommodates human interventions in workflows, which are crucial for decision-making processes that require analytical oversight or ethical consideration.

Whether you are building a chatbot with real memory, an interactive story engine, or a team of agents tackling a complex problem, LangGraph turns headache-inducing plumbing into a clean, visual state machine.

Getting Started

To start with LangGraph, you will need a basic setup that typically involves installing such essential libraries as langgraph and langchain-openai. From there, you can define the nodes (tasks) and edges (connections) within the graph, effectively implementing checkpoints for short-term memory and utilizing Zep for more persistent memory needs.

When operating LangGraph, keep in mind the following:

  • Design with Flexibility: Leverage the powerful graph structure to account for potential workflow branches and interactions that are not strictly linear.
  • Interact with Tools Thoughtfully: Enhance but do not replace LLM capabilities with external tools. Provide each tool with comprehensive descriptions to enable precise usage.
  • Employ Rich Memory Solutions: Use memory efficiently, be mindful of the LLM's context window, and consider integrating external solutions for automatic fact management.

Now that we have covered the basics of LangGraph, let's dive into a practical example. To achieve this, we will develop an AI agent specifically designed for customer support.

This agent will receive email requests, analyze the problem description in the email body, and then determine the request's priority and appropriate topic/category/sector.

So buckle up and let's go!

buckle up

To begin, we need to define what a 'Tool' is. You can think of it as a specialized "assistant manager" for your agent, allowing it to interact with external functionalities.

The @tool decorator is essential here. LangChain simplifies custom tool creation, meaning that first, you define a Python function, and then apply the @tool decorator.

tools

Let's illustrate this by creating our first tool. This tool will help the agent classify the priority of an IT support ticket based on its email content:

    from langchain_core.tools import tool
    
    @tool
    def classify_priority(email_body: str) -> str:
        """Classify the priority of an IT support ticket based on email content."""
        prompt = ChatPromptTemplate.from_template(
            """Analyze this IT support email and classify its priority as High, Medium, or Low.
            
            High: System outages, security breaches, critical business functions down
            Medium: Non-critical issues affecting productivity, software problems
            Low: General questions, requests, minor issues
            
            Email: {email}
            
            Respond with only: High, Medium, or Low"""
        )
        chain = prompt | llm
        response = chain.invoke({"email": email_body})
        return response.content.strip()

Excellent! Now we have a prompt that instructs the AI to receive the email body, analyze it, and classify its priority as High, Medium, or Low.

That’s it! You have just composed a tool your agent can call!

Next, let's create a similar tool to identify the main topic (or category) of the support request:


    @tool
    def identify_topic(email_body: str) -> str:
        """Identify the main topic/category of the IT support request."""
        prompt = ChatPromptTemplate.from_template(
            """Analyze this IT support email and identify the main topic category.
            
            Categories: password_reset, vpn, software_request, hardware, email, network, printer, other
            
            Email: {email}
            
            Respond with only the category name (lowercase with underscores)."""
        )
        chain = prompt | llm
        response = chain.invoke({"email": email_body})
        return response.content.strip()

Now we need to create a state, and in LangGraph this little piece is, kind of, a big deal.

Think of it as the central nervous system of your graph. It is how nodes talk to each other, passing notes like overachievers in class.

According to the docs:

“A state is a shared data structure that represents the current snapshot of your application.”

In practice? The state is a structured message that moves between nodes. It carries the output of one step as the input for the next one. Basically, it is the glue that holds your entire workflow together.

Therefore, before constructing the graph, we must first define the structure of our state. In this example, our state will include the following:

  • The user’s request (email body)
  • The assigned priority
  • The identified topic (category)

It is simple and clean, so you can move through the graph like a pro.

    from typing import TypedDict

    # Define the state structure
    class TicketState(TypedDict):
        email_body: str
        priority: str
        topic: str
        
    
    # Initialize state
    initial_state = TicketState(
        email_body=email_body,
        priority="",
        topic=""
    )

Nodes vs. Edges: Key Components of LangGraph

The fundamental building blocks of LangGraph include nodes and edges.

  • Nodes: They are the operational units within the graph, performing the actual work. A node typically consists of Python code that can execute any logic, ranging from computations to interactions with language models (LLMs) or external integrations. Essentially, nodes are like individual functions or agents in traditional programming.
  • Edges: Edges define the flow of execution between nodes, determining what happens next. They act as the connectors that allow the state to transition from one node to another based on predefined conditions. In the context of LangGraph, edges are crucial in orchestrating the sequence and decision flow between nodes.

To grasp the functionality of edges, let’s consider a simple analogy of a messaging application:

  • Nodes are akin to users (or their devices) actively participating in a conversation.
  • Edges symbolize the chat threads or connections between users that facilitate communication.

When a user selects a chat thread to send a message, an edge is effectively created, linking them to another user. Each interaction, be it sending a text, voice, or video message, follows a predefined sequence, comparable to the structured schema of LangGraph’s state. It ensures uniformity and interpretability of data passed along edges.

Unlike the dynamic nature of event-driven applications, LangGraph employs a static schema that remains consistent throughout execution. It simplifies communication among nodes, enabling developers to rely on a stable state format, thereby ensuring seamless edge communication.

Designing a Basic Workflow

Flow engineering in LangGraph can be conceptualized as designing a state machine. In this paradigm, each node represents a distinct state or processing step, while edges define the transitions between those states. This approach is particularly beneficial for developers aiming to strike a balance between deterministic task sequences and the dynamic decision-making capabilities of AI. Let's begin constructing our flow by initializing a StateGraph with the TicketState class we defined earlier.

    from langgraph.graph import StateGraph, START, END
    
    workflow = StateGraph(TicketState)

Node Addition: Nodes are fundamental building blocks, defined to execute such specific tasks as classifying ticket priority or identifying its topic.

Each node function receives the current state, performs its operation, and returns a dictionary to update the state:

   def classify_priority_node(state: TicketState) -> TicketState:
        """Node to classify ticket priority."""
        priority = classify_priority.invoke({"email_body": state["email_body"]})
        return {"priority": priority}

    def identify_topic_node(state: TicketState) -> TicketState:
        """Node to identify ticket topic."""
        topic = identify_topic.invoke({"email_body": state["email_body"]})
        return {"topic": topic}
        
        
    workflow.add_node("classify_priority", classify_priority_node)
    workflow.add_node("identify_topic", identify_topic_node)

The classify_priority_node and identify_topic_node methods will change the TicketState and send the parameter input.

Edge Creation: Define edges to connect nodes:


    workflow.add_edge(START, "classify_priority")
    workflow.add_edge("classify_priority", "identify_topic")
    workflow.add_edge("identify_topic", END)

The classify_priority establishes the start, whereas the identify_topic determines the end of our workflow so far.

Compilation and Execution: Once nodes and edges are configured, compile the workflow and execute it.


    graph = workflow.compile()
    result = graph.invoke(initial_state)

Great! You can also generate a visual representation of our LangGraph flow.

graph.get_graph().draw_mermaid_png(output_file_path="graph.png")

If you were to run the code up to this point, you would observe a graph similar to the one below:

first_graph.png

This illustration visualizes a sequential execution: start, followed by classifying priority, then identifying the topic, and, finally, ending.

One of the most powerful aspects of LangGraph is its flexibility, which allows us to create more complex flows and applications. For instance, we can modify the workflow to add edges from START to both nodes with the following line:

    workflow.add_edge(START, "classify_priority")
    workflow.add_edge(START, "identify_topic")

This change will imply that the agent executes classify_priority and identify_topic simultaneously.

Another highly valuable feature in LangGraph is the ability to use conditional edges. They allow the workflow to branch based on the evaluation of the current state, enabling dynamic routing of tasks.

Let's enhance our workflow. We will create a new tool that analyzes the content, priority, and topic of the request to determine whether it is a high-priority issue requiring escalation (i.e., opening a ticket for a human team). If not, an automated response will be generated for the user.


    @tool
    def make_escalation_decision(email_body: str, priority: str, topic: str) -> str:
        """Decide whether to auto-respond or escalate to IT team."""
        prompt = ChatPromptTemplate.from_template(
            """Based on this IT support ticket, decide whether to:
            - "auto_respond": Send an automated response for simple/common or medium priority issues
            - "escalate": Escalate to the IT team for complex/urgent issues
            
            Email: {email}
            Priority: {priority}
            Topic: {topic}
            
            Consider: High priority items usually require escalation, while complex technical issues necessitate human review.
            
            Respond with only: auto_respond or escalate"""
        )
        chain = prompt | llm
        response = chain.invoke({
            "email": email_body,
            "priority": priority,
            "topic": topic
        })
        return response.content.strip()
        

Furthermore, if the request is determined to be of low or medium priority (leading to an "auto_respond" decision), we will perform a vector search to retrieve historical answers. This information will then be used to generate an appropriate automated response. However, it will require two additional tools:


    @tool
    def retrieve_examples(email_body: str) -> str:
        """Retrieve relevant examples from past responses based on email_body."""
        try:
            examples = iris.cls(__name__).Retrieve(email_body)
            return examples if examples else "No relevant examples found."
        except:
            return "No relevant examples found."

    @tool
    def generate_reply(email_body: str, topic: str, examples: str) -> str:
        """Generate a suggested reply based on the email, topic, and RAG examples."""
        prompt = ChatPromptTemplate.from_template(
            """Generate a professional IT support response based on:
            
            Original Email: {email}
            Topic Category: {topic}
            Example Response: {examples}
            
            Create a helpful, professional response that addresses the user's concern.
            Keep it concise and actionable."""
        )
        chain = prompt | llm
        response = chain.invoke({
            "email": email_body,
            "topic": topic,
            "examples": examples
        })
        return response.content.strip()

Now, let's define the corresponding nodes for those new tools:

    
    def decision_node(state: TicketState) -> TicketState:
        """Node to decide on escalation or auto-response."""
        decision = make_escalation_decision.invoke({
            "email_body": state["email_body"],
            "priority": state["priority"],
            "topic": state["topic"]
        })
        return {"decision": decision}
        
    
    def rag_node(state: TicketState) -> TicketState:
        """Node to retrieve relevant examples using RAG."""
        examples = retrieve_examples.invoke({"email_body": state["email_body"]})
        return {"rag_examples": examples}

    def generate_reply_node(state: TicketState) -> TicketState:
        """Node to generate suggested reply."""
        reply = generate_reply.invoke({
            "email_body": state["email_body"],
            "topic": state["topic"],
            "examples": state["rag_examples"]
        })
        return {"suggested_reply": reply}
        
    
    def execute_action_node(state: TicketState) -> TicketState:
        """Node to execute final action based on decision."""
        if state["decision"] == "escalate":
            action = f"&#x1f6a8; ESCALATED TO IT TEAM\nPriority: {state['priority']}\nTopic: {state['topic']}\nTicket created in system."
            print(f"[SYSTEM] Escalating ticket to IT team - Priority: {state['priority']}, Topic: {state['topic']}")
        else:
            action = f"&#x2705; AUTO-RESPONSE SENT\nReply: {state['suggested_reply']}\nTicket logged for tracking."
            print(f"[SYSTEM] Auto-response sent to user - Topic: {state['topic']}")
        
        return {"final_action": action}
        
        
        
    workflow.add_node("make_decision", decision_node)
    workflow.add_node("rag", rag_node)
    workflow.add_node("generate_reply", generate_reply_node)
    workflow.add_node("execute_action", execute_action_node)

The conditional edge will then use the output of the make_decision node to direct the flow:

    workflow.add_conditional_edges(
        "make_decision",
        lambda x: x.get("decision"),
        {
            "auto_respond": "rag",
            "escalate": "execute_action"
        }
    )

If the make_escalation_decision tool (via decision_node) results in "auto_respond", the workflow will proceed through the rag node (to retrieve examples), then to generate_reply (to craft the response), and finally to execute_action (to log the auto-response).

Conversely, if the decision is "escalate", the flow will bypass the RAG and take generation steps, moving directly to execute_action to handle the escalation. To complete the graph by adding the remaining standard edges, do the following:

    workflow.add_edge("rag", "generate_reply")
    workflow.add_edge("generate_reply", "execute_action")
    workflow.add_edge("execute_action", END)

Dataset Note: For this project, the dataset we used to power the Retrieval-Augmented Generation (RAG) was sourced from the Customer Support Tickets dataset on Hugging Face. The dataset was filtered to include exclusively the items categorized as 'Technical Support' and restricted to English entries. It ensured that the RAG system retrieved only highly relevant and domain-specific examples for technical support tasks.

At this point, our graph should resemble the one below:

graph.png

When you execute this graph with an email that results in a high priority classification and an "escalate" decision, you will see the following response:

image.png

At the same time, a request that is classified as low priority and results in an "auto_respond" decision will trigger a reply resembling the one below:

image.png

So... Is It All Sunshine?

Not entirely. There a few bumps to watch out for:

  • Data Privacy: Be careful with sensitive info — these agents require guardrails.
  • Compute Costs: Some advanced setups require serious resources.
  • Hallucinations: LLMs can occasionally make things up (still smarter than most interns, though).
  • Non-Determinism: The same input might return different outputs, which is great for creativity, but tricky for strict processes.

However, most of these weak spots can be managed with good planning, the right tools, and — you guessed it — a bit of reflection.

LangGraph turns AI agents from buzzwords into real, working solutions. Whether you want to automate customer support, handle IT tickets, or build autonomous apps, this framework makes it doable and, actually, enjoyable.

Have you got any questions or feedback? Let’s talk. The AI revolution needs builders like you.

4
3 458
Discussion Harshitha · May 30, 2025

Hey everyone,

I'm diving deeper into Caché ObjectScript and would love to open a discussion around the most useful tips, tricks, and best practices you’ve learned or discovered while working with it.

Whether you're an experienced developer or just getting started, ObjectScript has its own set of quirks and powerful features—some well-documented, others hidden gems. I’m looking to compile a helpful set of ideas from the community.

Some areas I’m especially interested in:

3
4 145
Article Eric Fortenberry · May 30, 2025 3m read

Have you ever needed to change an IP or port before deploying an interface to production? Needed to remove items from an export? What about modifying the value(s) in a lookup table before deploying? Have you wanted to disable an interface before deploying? What about adding a comment, category, or alert setting to an interface before deploying to production?

If you’ve ever needed to make any changes to an interface or lookup table before deploying to production, then Export Editor is for you!

0
0 76
Question Eric Tulowetzke · May 23, 2025

Hi all,

My team is exploring options for handling timezone offsets in DTL and we’re wondering if there are any built-in methods available — ideally low-code or no-code solutions. Specifically, we're looking for a way to adjust timestamps based on the date and whether Daylight Saving Time (DST) is in effect.

For example, if an HL7 message has an MSH-7 value of 20250518144529, it should be converted to 20250518144529-0500 (Central Daylight Time), but if the timestamp were 20250218144529, it should be 20250218144529-0600 (Central Standard Time).

6
1 128