Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify Echo agent tutorial instruction and include install and uninstall command. #679

Merged
merged 2 commits into from
Feb 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ Microsoft TypeAgent Repo is a mono-repo, with components organized with the foll
- [`python`](./python) Python code ([Readme](./python/README.md))
- [`dotnet`](./dotnet) Dotnet (C#) code ([Readme](./dotnet/README.md))

For developer who want to experiment with TypeAgent and see how typed action schema drives actions, the [Agent Shell](./ts/packages/shell) example allow additional agent to be installed/registered to extent functionality. The `Echo` agent [tutorial](./docs/tutorial/agent.md) is a starting point to create a plugin agent, and [Agent SDK](./ts/packages/agentSdk/) provides the details of the interface between [Dispatcher](./ts/packages/dispatcher) and the agent.

## Contributing

This project welcomes contributions and suggestions. Most contributions require you to
Expand Down
243 changes: 243 additions & 0 deletions docs/tutorial/agent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
# External Agents

The TypeAgent repo includes several example [agents](../../ts/packages/agents/). You can also build **your own application agents** **_outside_** the TypeAgent repo by using the [agent-sdk](../../ts/packages/agentSdk/README.md). You can package these agents as npm packages and surface them in the [TypeAgent Shell](../../ts/packages/shell) and [TypeAgent CLI](../../ts/packages/cli).

This document describes how you can build your own application agents.

## Prerequisites

Begin by exploring the following:

- **Agent-Sdk**: Read about the architecture of the [**agent-sdk**](../../ts/packages/agentSdk/README.md).
- **Example Agents**:
- Review agents under the [agents](../../ts/packages/agents) directory. The [List](../../ts/packages/agents/list/) agent provides a good example and template for building an agent.
- The [Echo](../../ts/examples/agentExamples/echo/) agent illustrates the basics of building your own external application agents.

## Steps to build an `Echo` agent:

For the rest of the documentation, we will assume that the external agent is named **echo**. The echo agent performs a single action: echos any input back to the user.

You can see the end result of this tutorial in [Echo](../../ts/examples/agentExamples/echo/) with some modification (NOTE: The only difference is the @typeagent/agent-sdk dependency)

### Step 1: Create and author the `Echo` agent package

Follow the following steps to create the `Echo` agent packages manually. Start by create a directory `echo`. Then populate the directory with the following content:

**package.json** [package.json](../../ts/examples/agentExamples/echo/package.json) :

The `package.json` contains references to **handler** and **manifest** files in the `exports` field.

```json
{
"name": "echo",
"version": "0.0.1",
"description": "Echo example for TypeAgent",
"license": "MIT",
"author": "Microsoft",
"type": "module",
"exports": {
"./agent/manifest": "./src/echoManifest.json",
"./agent/handlers": "./dist/echoActionHandler.js"
},
"scripts": {
"build": "npm run tsc",
"clean": "rimraf --glob dist *.tsbuildinfo *.done.build.log",
"tsc": "tsc -b"
},
"keywords": [],
"dependencies": {
"@typeagent/agent-sdk": "0.0.1"
},
"devDependencies": {
"rimraf": "^5.0.5",
"typescript": "^5.4.2"
}
}
```

Every application agent requires the following files to be present in the agent's [**source**](../../ts/examples/agentExamples/echo/src/) directory.

- **Agent Manifest File**: The manifest file is used to register the agent with the TypeAgent ecosystem.
- **Action Schema File**: The action schema file is used to define the actions that the agent can perform.
- **Agent Action Handler**: Your code that perform's the agent's actions.

**Agent Manifest File** : [`src/echoManifest.json`](../../ts/examples/agentExamples/echo/src/echoManifest.json)

The manifest file contain reference in `schemaFile` to the path to **schema** file (relative path to the **manifest** file) and the `schemaType` corresponds to the union type of all the actions.

```json
{
"emojiChar": "🦜",
"schema": {
"description": "A basic echo agent.",
"schemaFile": "./echoActionSchema.ts",
"schemaType": "EchoAction"
}
}
```

**Agent Action Schema File** : [`src/echoActionSchema.ts`](../../ts/examples/agentExamples/echo/src/echoActionSchema.ts)

```ts
export type EchoAction = GenEchoAction;

// If the user asks to echo a message back, the system will return a GenEchoAction. The text parameter is the message to be echoed back.
// will contain the text to be echoed back to the user.
export type GenEchoAction = {
actionName: "echoGen";
parameters: {
text: string;
};
};
```

**Agent action handler** : [`src/echoActionHandler.ts`](../../ts/examples/agentExamples/echo/src/echoActionHandler.ts)

```ts
import { ActionContext, AppAgent, TypeAgentAction } from "@typeagent/agent-sdk";
import {
createActionResultFromTextDisplay,
createActionResultFromError,
} from "@typeagent/agent-sdk/helpers/action";
import { EchoAction } from "./echoActionSchema.js";

export function instantiate(): AppAgent {
return {
initializeAgentContext: initializeEchoContext,
executeAction: executeEchoAction,
};
}

type EchoActionContext = {
echoCount: number;
};

async function initializeEchoContext(): Promise<EchoActionContext> {
return { echoCount: 0 };
}

async function executeEchoAction(
action: TypeAgentAction<EchoAction>,
context: ActionContext<EchoActionContext>
) {
// The context created in initializeEchoContext is returned in the action context.
const echoContext = context.sessionContext.agentContext;
switch (action.actionName) {
case "echoGen":
const displayText = `>> Echo ${++echoContext.echoCount}: ${
action.parameters.text
}`;
return createActionResultFromTextDisplay(displayText, displayText);

default:
return createActionResultFromError("Unable to process the action");
}
}
```

**Typescript build config file** [`tsconfig.json`](../../ts/examples/agentExamples/echo/tsconfig.json)

```json
{
"compilerOptions": {
"composite": true,
"target": "es2021",
"lib": ["es2021"],
"module": "node16",
"declaration": true,
"declarationMap": true,
"esModuleInterop": true,
"exactOptionalPropertyTypes": true,
"forceConsistentCasingInFileNames": true,
"incremental": true,
"noEmitOnError": true,
"noUnusedLocals": true,
"skipLibCheck": true,
"strict": true,
"sourceMap": true,
"rootDir": "./src",
"outDir": "./dist"
},
"include": ["./src/**/*"],
"ts-node": {
"esm": true
}
}
```

#### Folder structure for **Echo** agent:

![alt text](./imgs/image-files.png)

<a id="install_agent"></a>

#### Step 2: Build the Agent

First make sure the [TypeAgent's typescript code](../../ts) is built.

- Go to `<repo>/ts`
- `pnpm i`
- `pnpm run build`

Then create a link globally to the `@typeagent/agent-sdk` package for the `Echo` agent to consume.

- Go to `<repo>/ts/packages/agentSdk`
- `npm link`

In the `Echo` package, run the following to link to `@typeagent/agent-sdk` package and build

- `npm link @typeagent/agent-sdk`
- `npm install`
- `npm run build`

### Step 3: Install `Echo` agent in TypeAgent cli or shell.

Start TypeAgent [Shell](../../ts/packages/shell) or [CLI](../../ts/packages/cli)

```bash
# you can run these commands from the `ts` folder
# in the TypeAgent root.

pnpm run cli interactive

or

pnpm run shell
```

In the [Shell](../../ts/packages/shell) or [CLI](../../ts/packages/cli), install the echo agent and check the status by issuing the command:

```
@install echo <path to echo package>
@config agent
```

The `Echo` agent should be in the list and enabled.

### Step 4: See the `Echo` agent in action

`Echo` agent is now ready. Test it out by issuing some request to see the `Echo` agent in action

When to run the cli this is how interaction with the `Echo` agent will look like:
![alt text](./imgs/image-cli.png)

When to run the shell this is how interaction with the `Echo` agent will look like:
![alt text](./imgs/image-shell.png)

The `Echo` agent will be reloaded again after installation. It can be uninstalled using the command:

```
@uninstall echo
```

## Next step

Start modifying the `Echo` agent and add new action schema and action handlers.

## Trademarks

This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft
trademarks or logos is subject to and must follow
[Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general).
Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship.
Any use of third-party trademarks or logos are subject to those third-party's policies.
2 changes: 1 addition & 1 deletion ts/examples/agentExamples/echo/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Echo Agent

The Echo Agent demonstrates how to use the [agent-sdk](../../../packages/agentSdk/ExternalAgents_README.md) to write agents as installable packages.
The Echo Agent demonstrates how to use the [agent-sdk](../../../../docs/tutorial/agent.md) to write agents as installable packages.

## Trademarks

Expand Down
3 changes: 1 addition & 2 deletions ts/examples/agentExamples/echo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,10 @@
"type": "module",
"exports": {
"./agent/handlers": "./dist/echoActionHandler.js",
"./agent/manifest": "./dist/echoManifest.json"
"./agent/manifest": "./src/echoManifest.json"
},
"scripts": {
"build": "npm run tsc",
"postbuild": "copyfiles -u 1 \"src/**/*Schema*.ts\" \"src/**/*Manifest*.json\" dist",
"clean": "rimraf --glob dist *.tsbuildinfo *.done.build.log",
"prettier": "prettier --check . --ignore-path ../../../.prettierignore",
"prettier:fix": "prettier --write . --ignore-path ../../../.prettierignore",
Expand Down
65 changes: 13 additions & 52 deletions ts/examples/agentExamples/echo/src/echoActionHandler.ts
Original file line number Diff line number Diff line change
@@ -1,81 +1,42 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import {
ActionContext,
AppAction,
AppAgent,
SessionContext,
ActionResult,
} from "@typeagent/agent-sdk";
import { ActionContext, AppAgent, TypeAgentAction } from "@typeagent/agent-sdk";
import {
createActionResultFromTextDisplay,
createActionResultFromError,
} from "@typeagent/agent-sdk/helpers/action";

import { EchoAction } from "./echoActionsSchema.js";
import { EchoAction } from "./echoActionSchema.js";

export function instantiate(): AppAgent {
return {
initializeAgentContext: initializeEchoContext,
updateAgentContext: updateEchoContext,
executeAction: executeEchoAction,
};
}

type EchoActionContext = {
echoCount: number;
echoRequests: Set<string> | undefined;
};

async function initializeEchoContext() {
return {
echoCount: 0,
echoRequests: undefined,
};
}

async function updateEchoContext(
enable: boolean,
context: SessionContext<EchoActionContext>,
): Promise<void> {
if (enable) {
context.agentContext.echoRequests = new Set<string>();
context.agentContext.echoCount = 0;
}
context.agentContext.echoCount++;
async function initializeEchoContext(): Promise<EchoActionContext> {
return { echoCount: 0 };
}

async function executeEchoAction(
action: AppAction,
action: TypeAgentAction<EchoAction>,
context: ActionContext<EchoActionContext>,
) {
let result = await handleEchoAction(
action as EchoAction,
context.sessionContext.agentContext,
);
return result;
}

async function handleEchoAction(
action: EchoAction,
echoContext: EchoActionContext,
) {
let result: ActionResult | undefined = undefined;
let displayText: string | undefined = undefined;
// The context created in initializeEchoContext is returned in the action context.
const echoContext = context.sessionContext.agentContext;
switch (action.actionName) {
case "echoGen":
displayText = `>> Echo: ${action.parameters.text}`;
result = createActionResultFromTextDisplay(
displayText,
displayText,
);
break;
const displayText = `>> Echo ${++echoContext.echoCount}: ${
action.parameters.text
}`;
return createActionResultFromTextDisplay(displayText, displayText);

default:
result = createActionResultFromError(
"Unable to process the action",
);
break;
return createActionResultFromError("Unable to process the action");
}
return result;
}
2 changes: 1 addition & 1 deletion ts/examples/agentExamples/echo/src/echoManifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"emojiChar": "🦜",
"schema": {
"description": "A basic echo agent.",
"schemaFile": "echoActionsSchema.ts",
"schemaFile": "./echoActionSchema.ts",
"schemaType": "EchoAction"
}
}
2 changes: 1 addition & 1 deletion ts/examples/agentExamples/measure/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Work in progress.

## Installation

- Follow the standard exteneral [Agent installation steps](../../../packages/agentSdk/ExternalAgents_README.md#install_agent)
- Follow the standard external [Agent installation steps](../../../../docs/tutorial/agent.md#step-3-install-echo-agent-in-typeagent-cli-or-shell)

## Trademarks

Expand Down
Loading
Loading