Skip to content

Latest commit

 

History

History
278 lines (199 loc) · 8.61 KB

File metadata and controls

278 lines (199 loc) · 8.61 KB

Lab 1: Hello, agent

Cloud course · 5 minutes, plus 5 on your own · CLI, Python, or TypeScript

You create an agent with no tools, start a conversation, and read back what the Agent Engine recorded. When this lab is done, you have an agent at version 1 and you know the four things every later lab reuses: environment, agent, session, events.

Before you start

  • You finished Lab 0: the doctor says you are ready.
  • One terminal is in your path's folder (cli/, python/ with the virtual environment active, or typescript/). A second one is at the repository root.

Step 1: Create your agent and say hello

In your path's folder:

CLI Python TypeScript
./l1_hello.sh python l1_hello.py npm run l1

You see something like this. The agent's wording varies.

hello-agent-ana v1: no tools: just a conversation
[you]    Hi! What is the Data + Agent Hackathon, and what can you see right now?
[agent]  It's a one-day build where teams combine live streaming data with AI agents. I can't see any live data yet: the next step connects me to a Kafka stream.

Check

Read your agent back. It prints the name, the version, and that it has no tools.

./lab-ork agent get @agent_id -o json | jq -e '{name, version, tools: (.tools | length)} | select(.tools == 0)'
{
  "name": "hello-agent-ana",
  "version": 1,
  "tools": 0
}

Before the step, the same command says No agent_id yet: nothing has been created.

What just happened: four API calls.

  1. Environment: where your agent's sessions run.
  2. Agent: a model plus a system prompt, defined in agent/cloud/l1-hello.json. All three paths read that file.
  3. Session: one conversation, pinned to a specific agent version.
  4. Events: you send a user.message; the agent streams back agent.message events until the session goes idle.
The code (Python)
environment_id = ensure_environment(client, state, f"hello-env-{config.participant}")

layer = load_layer("l1-hello", config.stack)
agent = ensure_agent(client, state, agent_params(layer, config))

session = open_session(client, state, environment_id, agent, "L1: hello")
run_turn(client, session.id, question, send_first=config.stack == "local")

open_session (python/common.py) is one call, client.sessions.create(environment_id=..., agent={"type": "agent", "id": agent.id, "version": agent.version}, title=...), and it remembers the session id for your checks. run_turn opens the event stream before sending the message, so no event is missed, then prints events until the agent's turn ends. (send_first is off on this course. It is for the Local course's engine.)

The code (TypeScript)
const environmentId = await ensureEnvironment(client, state, `hello-env-${config.participant}`);

const layer = loadLayer('l1-hello', config.stack);
const agent = await ensureAgent(client, state, agentParams(layer, config));

const session = await openSession(client, state, environmentId, agent, 'L1: hello');
await runTurn(client, session.id, question, { sendFirst: config.stack === 'local' });

openSession and runTurn (typescript/src/common.ts) work the same way as the Python versions.

The commands (CLI)
ork agent environments create --name hello-env-ana -o json

ork agent create --name hello-agent-ana --model "$ORCA_MODEL" \
  --system "$(jq -r .system ../agent/cloud/l1-hello.json)" -o json

ork agent sessions create --agent <agent id> --agent-version 1 \
  --environment-id <environment id> --title "L1: hello" -o json

ork agent sessions events send message --session <session id> --text "Hi! ..."
ork agent sessions events stream --session <session id> --timeout 15s

cli/lib.sh wraps these commands, remembers the ids, and prints the stream the same way as the other paths.

Step 2: Read the conversation back

A session is a list of events. From the repository root, list the types of the events in the conversation you just had, oldest first:

./lab-ork agent sessions events list --session @session_id --order asc -o json | jq -r '.data[].type'
user.message
session.status_running
agent.message
session.status_idle

Your message, the agent's reply, and the event that ends the turn. You may see span. events too, which time the model request, and agent.thinking, the model working out its answer before it gives it.

Check

"The agent replied" is three facts together: the turn ended normally, and a reply came after your message. This prints the reply when all three hold.

./lab-ork agent sessions events list --session @session_id --order asc --limit 200 -o json | jq -e '
  .data
  | select((map(select(.type == "session.status_idle")) | last | .stop_reason.type) == "end_turn")
  | .[(map(.type) | rindex("user.message")):]
  | map(select(.type == "agent.message")) | last
  | select(. != null)
  | {reply: .content[0].text}'

Reading it line by line: take the events; keep going only if the last idle event stopped for end_turn; look at what came after your last message; take the last agent.message there; print its text. A turn that ended for another reason, or ended without a reply, prints nothing.

Step 3: Run it again

Ask your own question this time:

CLI Python TypeScript
./l1_hello.sh "What will you be able to do in Lab 3?" python l1_hello.py "What will you be able to do in Lab 3?" npm run l1 -- "What will you be able to do in Lab 3?"

The first line still says v1. Re-running is safe: the scripts remember your agent in .orca-state/, and only create a new version when its definition changes. The conversation is new; the agent is not.

Check

Your agent now has two sessions, and both are pinned to version 1. It prints them once there are two.

./lab-ork agent sessions list --agent @agent_id -o json | jq -e '[.data[] | {title, version: .agent.version}] | select(length >= 2)'
[
  {
    "title": "L1: hello",
    "version": 1
  },
  {
    "title": "L1: hello",
    "version": 1
  }
]

Check your understanding

1. What ties a session to one definition of the agent?

  • A. The agent's name
  • B. The agent version the session was created with
  • C. The environment
Answer

B. A session records the agent id and version. Changing the agent later creates a new version and does not touch a conversation that is already running.

2. You run the script twice without changing anything. How many agents and versions exist?

  • A. Two agents
  • B. One agent, at version 2
  • C. One agent, at version 1
Answer

C. The script stores a fingerprint of the definition in the agent's metadata. Same fingerprint, no update. Each run does start a new session.

3. Which event tells you the agent's turn is over?

  • A. agent.message
  • B. session.status_idle
  • C. user.message
Answer

B. It carries a stop_reason. end_turn means the turn finished normally; in Lab 4 you will see requires_action, which means the session is waiting for you.

Try it yourself

Change how your agent talks, and watch its version change. Make it answer in a single sentence, run the lab script again, then confirm the agent is at a newer version.

Check

It prints the version once it is 2 or more.

./lab-ork agent get @agent_id -o json | jq -e 'select(.version >= 2) | {name, version}'
Solution

The agent is the JSON file. In agent/cloud/l1-hello.json, change "Answer in two or three sentences." to "Answer in one sentence.", then run the Lab 1 script again. The first line now says v2.

Put the file back before the next lab (git checkout agent/cloud/l1-hello.json). Your version numbers will run one or two ahead of the ones the labs show. That is fine: the checks never depend on an exact number after this lab.

On the CLI path, do this before Lab 3. Once your agent has tools, ork cannot take them away, so going back to Lab 1 starts a fresh agent at version 1, and the script says so.

Recap

  • An agent is configuration: a model, a system prompt, and (later) tools.
  • Every change to it is a new version. A session is pinned to one version.
  • A conversation is a list of events, and session.status_idle ends a turn.

What's next

Lab 2: Hello, streaming SQL