Skip to content

Commit

Permalink
Simplify Echo agent tutorial instruction and include install and unin…
Browse files Browse the repository at this point in the history
…stall command. (#679)
  • Loading branch information
curtisman authored Feb 7, 2025
1 parent 8341dfa commit 86f1343
Show file tree
Hide file tree
Showing 14 changed files with 265 additions and 404 deletions.
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.
File renamed without changes
File renamed without changes
File renamed without changes
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

0 comments on commit 86f1343

Please sign in to comment.