# Gadget Drone: The Agentic Workflow Loop

[Gadget Drone](./gadget-drone.md) exists primarily to run the Agentic Workflow Loop (AWL) within the Gadget Code ecosystem.

The User is using a chat interface in an HTML5 web application connected to the Gadget Code web server using Socket.IO. Gadget Drone is also connected to the Gadget Code web server using Socket.IO. The User submits prompts for processing in the chat interface, and the web server packages them as Work Order jobs for Gadget Drone to process.

As the drone is calling AI APIs to have the chat processed and receiving streaming responses, it emits messages to the web server to update the User's chat session context and the AI service provider's statistics.

## The Work Order

Each Gadget Drone registered by the User implements a named Bull job queue. Gadget Code will create a Work Order job for the Drone to process, and place it into a selected drone's job queue for processing.

The Work Order is a JSON object that contains information about the project, AI service provider and model, and also the User's prompt.

````typescript
/*
 * Chat session context is made of chat messages with a timestamp and role. The
 * role is "system", "user", "assistant", or "tool". The assistant can have
 * reasoning or "thinking" content. When thinking content is being included, we
 * merge the thinking + response by enclosing the thinking content in a
 * <thinking> element in the content.
 *
 * ```
 * <thinking>I need to research the project...</thinking>
 * I found the bug!
 * ```
 */
interface IChatMessage {
  createdAt: Date;
  role: string;
  content: string;
}

interface IWorkOrder {
  project: {
    _id: string;
    name: string;
    slug: string;
    gitUrl: string;
  };
  provider: {
    sdk: "ollama" | "openai";
    baseUrl: string;
    apiKey: string;
    modelId: string;
    params: {
      temperature: number;
      topP: number;
      topK: number;
    };
  };
  chatSession: {
    _id: string;
    name: string;
    context: IChatMessage[];
  };
  chatTurn: {
    _id: string;
    mode: string;
    prompt: string;
  };
}
````

## The Workflow Loop

When a Work Order job is received a Gadget Drone, it performs a series of steps in preparation to work on the prompt contained in the work order.

1. Check if the workspace directory currently has the project cloned. If not, clone the project from git into the workspace directory.

2. Instantiate the correct AI API client object configured with the credentials provided in the work order.

```typescript
/**
 * Called when the drone receives a Work Order job for processing. The Gadget
 * Code web server will have already created the `ChatTurn` within the
 * `ChatSession` happening within the `Project`, and is passing all information
 * needed by the drone to execute the prompt.
 */
async function onWorkOrder(job: Bull.Job<IWorkOrder>): Promise<void> {
  // this turn's context (system, history, prompt, work)
  const messages = [];

  const systemPrompt = buildSystemPrompt(session);
  messages.push({ role: "system", content: systemPrompt });

  // recall full session history into messages array
  buildSessionContext(job, messages);

  // push the User's latest prompt to the context
  messages.push({ role: "user", content: job.data.prompt });

  let keepProcessing = true;
  do {
    const response = await aiApiCall(messages);
    keeProcessing = response.tool_calls.length > 0;
    for (const tool_call of response.tool_calls) {
      const response = await callTool(tool_call.name, tool_call.args);
      messages.push({ role: "tool", content: response });
      /* emit turn-tool-call socket message */
    }
  } while (keepProcessing);

  /* emit turn-finished socket message */
}

function buildSessionContext(
  job: Bull.Job<IWorkOrder>,
  messages: IChatMessage[],
): void {
  for (const message of job.data.chatSession.context) {
    if (message.role === "system") {
      continue; // we don't
    }
    messages.push(message);
  }
}

/**
 * To optimize context, reduce clutter, and help the agent focus, full outputs
 * of older file reads and edits are summarized once a newer version is available.
 */
function pruneSessionContext(messages: IChatMessage[]): void {
  // TODO
}
```
