MCP-K8s

 view release on metacpan or  search on metacpan

examples/raider-configmap-demo.pl  view on Meta::CPAN

my $server = $k8s->server;
ok("Connected!");
label("Namespaces:", join(', ', @{ $k8s->namespaces }));
label("Tools:", scalar(@{ $server->tools }));
print "\n";

# ── Tool registry (for per-tool stats) ──────────────────────────────
my %tool_stats;    # name => { calls => N, total_ms => N }
my $total_calls = 0;

# Wrap each tool's code to print live progress with timing
for my $tool (@{ $server->tools }) {
  my $orig_code = $tool->code;
  my $name = $tool->name;
  $tool_stats{$name} = { calls => 0, total_ms => 0 };
  $tool->code(sub {
    my ($t, $args) = @_;
    $total_calls++;
    $tool_stats{$name}{calls}++;

    # Build detail string
    my @info;
    push @info, $args->{resource} if $args->{resource};
    push @info, $args->{name} if $args->{name};
    push @info, "ns=$args->{namespace}" if $args->{namespace};
    my $detail = @info ? ' ' . join(', ', @info) : '';

    printf "  ${YELLOW}[%d]${RESET} ${BOLD}%s${RESET}${DIM}%s${RESET} ",
      $total_calls, $name, $detail;

    my $t0 = [gettimeofday];
    my $result = $orig_code->($t, $args);
    my $elapsed = tv_interval($t0) * 1000;
    $tool_stats{$name}{total_ms} += $elapsed;

    printf "${DIM}(%s)${RESET}\n", fmt_ms($elapsed);
    return $result;
  });
}

# ── Wire up async MCP transport ─────────────────────────────────────
my $loop = IO::Async::Loop->new;
my $mcp = Net::Async::MCP->new(server => $server);
$loop->add($mcp);

# ── AI Engine ────────────────────────────────────────────────────────
my $model = $ENV{MCP_K8S_DEMO_MODEL} || 'claude-sonnet-4-6';
info("Model: $model");
print "\n";

my $engine = Langertha::Engine::Anthropic->new(
  model       => $model,
  mcp_servers => [$mcp],
);

# ── Raider ───────────────────────────────────────────────────────────
my $iteration_t0;

my $raider = Langertha::Raider->new(
  engine         => $engine,
  max_iterations => 15,
  on_iteration   => sub {
    my ($raider, $iteration) = @_;

    # Show timing for previous iteration
    if ($iteration_t0 && $iteration > 2) {
      my $prev_ms = tv_interval($iteration_t0) * 1000;
      info(sprintf("  iteration took %s", fmt_ms($prev_ms)));
    }

    $iteration_t0 = [gettimeofday];
    printf "\n${BLUE}--- Iteration %d ---%s\n", $iteration, $RESET;

    # Show token count if available
    if ($raider->has_last_prompt_tokens) {
      info(sprintf("  prompt tokens: %s", $raider->_last_prompt_tokens));
    }

    return;
  },
  mission => <<'MISSION',
You are demonstrating MCP::K8s capabilities. Follow these steps exactly:

1. First, call k8s_permissions to see what you can do.
2. Create a ConfigMap named "mcp-k8s-demo" with this data:
   - greeting: "Hello from MCP::K8s!"
   - version: "1.0"
   - created-by: "langertha-raider"
3. Read the ConfigMap back using k8s_get to verify it exists.
4. Update it using k8s_apply to add a new key: updated: "true"
5. Delete the ConfigMap to clean up.

After each step, briefly confirm what happened. Be concise.
If any step fails due to permissions, report it and skip to the next step.
MISSION
);

# ── Run the demo ─────────────────────────────────────────────────────
async sub main {
  await $mcp->initialize;

  banner("Raid: Full ConfigMap Lifecycle");

  my $raid_t0 = [gettimeofday];
  printf "${BLUE}--- Iteration 1 ---${RESET}\n";
  $iteration_t0 = [gettimeofday];

  my $response = await $raider->raid_f(
    'Please run through the full ConfigMap demo now.'
  );

  my $raid_elapsed = tv_interval($raid_t0) * 1000;

  # ── AI Response ──────────────────────────────────────────────────
  banner("AI Response");
  print $response, "\n";

  # ── Metrics Summary ──────────────────────────────────────────────
  banner("Session Metrics");

  my $m = $raider->metrics;

  label("Total time:", fmt_ms($raid_elapsed));
  label("Iterations:", $m->{iterations});
  label("Tool calls:", $m->{tool_calls});

  if ($raider->has_last_prompt_tokens) {
    label("Last prompt tokens:", $raider->_last_prompt_tokens);
  }

  # ── Per-tool breakdown ───────────────────────────────────────────
  my @used_tools = sort { $tool_stats{$b}{calls} <=> $tool_stats{$a}{calls} }
                   grep { $tool_stats{$_}{calls} > 0 } keys %tool_stats;

  if (@used_tools) {
    print "\n${BOLD}  Tool Breakdown:${RESET}\n";
    printf "  ${DIM}%-25s %6s %10s${RESET}\n", 'Tool', 'Calls', 'Time';
    printf "  ${DIM}%-25s %6s %10s${RESET}\n", '-' x 25, '-' x 6, '-' x 10;
    for my $name (@used_tools) {
      my $s = $tool_stats{$name};
      printf "  %-25s %6d %10s\n", $name, $s->{calls}, fmt_ms($s->{total_ms});
    }
    my $total_tool_ms = 0;
    $total_tool_ms += $_->{total_ms} for values %tool_stats;
    printf "  ${DIM}%-25s %6s %10s${RESET}\n", '-' x 25, '-' x 6, '-' x 10;
    printf "  ${BOLD}%-25s %6d %10s${RESET}\n",
      'TOTAL', $total_calls, fmt_ms($total_tool_ms);

    # LLM thinking time = total - tool time
    my $llm_ms = $raid_elapsed - $total_tool_ms;
    printf "\n  ${DIM}LLM thinking: %s  |  K8s API: %s${RESET}\n",
      fmt_ms($llm_ms), fmt_ms($total_tool_ms);
  }

  # ── Session history stats ────────────────────────────────────────
  my @hist = @{ $raider->session_history };
  if (@hist) {
    my %roles;
    $roles{$_->{role} // 'unknown'}++ for @hist;
    print "\n${BOLD}  Conversation:${RESET}\n";
    label("Messages:", scalar @hist);
    for my $role (sort keys %roles) {
      label("  $role:", $roles{$role});
    }
  }

  print "\n";
  ok("Demo complete!");
}

main()->get;



( run in 0.698 second using v1.01-cache-2.11-cpan-71847e10f99 )