{"id":"devops-ci-failure-grouper","title":"CI Failure Grouper","description":"Groups typed. CI noise. Typed v1 agent with eval coverage.","category":"devops","status":"validated","version":"1.0.0","source":"agentskit-registry","license":"MIT","tags":["devops","structured-output","v1"],"packages":["@agentskit/core","@agentskit/runtime","@agentskit/tools"],"files":["agent.ts","README.md","eval.ts"],"requires":{"zod":"^3","zod-to-json-schema":"^3"},"skill":{"name":"devops-ci-failure-grouper","description":"Groups typed. CI noise. Typed v1 agent with eval coverage.","systemPrompt":"You are CI Failure Grouper. CI noise. Output: Groups typed.\nGroup into themed clusters.\nNEVER invent facts — gaps and openQuestions for missing input. Always draft for human review.\n${UNTRUSTED_CONTENT_DIRECTIVE}\nCall submit_failure_grouper exactly once. Stop."},"flow":null,"a2a":{"id":"io.agentskit.registry.devops-ci-failure-grouper","name":"CI Failure Grouper","description":"Groups typed. CI noise. Typed v1 agent with eval coverage.","version":"1.0.0","homepage":"https://registry.agentskit.io","skills":[{"name":"devops-ci-failure-grouper","description":"Groups typed. CI noise. Typed v1 agent with eval coverage.","capabilities":{"streaming":true,"cancellation":true,"requiresApproval":false}}]},"sources":[{"path":"agent.ts","content":"import type { AdapterFactory, ChatMemory, Observer, ToolCall, ToolDefinition } from '@agentskit/core'\nimport { fenceUntrustedContent, UNTRUSTED_CONTENT_DIRECTIVE } from '@agentskit/core/security'\nimport { invokeStructured } from '@agentskit/runtime'\nimport { defineZodTool } from '@agentskit/tools'\nimport { z } from 'zod'\nimport { zodToJsonSchema } from 'zod-to-json-schema'\nimport type { JSONSchema7 } from 'json-schema'\n\n/** CI Failure Grouper — v1 validated. Pain: CI noise */\n\nexport interface Cluster { name: string; theme: string; items: string[] }\nexport interface AgentOutput { summary: string; clusters: Cluster[]; unassigned: string[] }\nexport interface AgentResult extends AgentOutput { requiresReview: boolean }\nexport interface DevopsCiFailureGrouperConfig {\n  adapter: AdapterFactory\n  memory?: ChatMemory\n  observers?: Observer[]\n  onConfirm?: (toolCall: ToolCall) => boolean | Promise<boolean>\n  maxSteps?: number\n}\n\nconst Output = z.object({\n  summary: z.string(),\n  clusters: z.array(z.object({ name: z.string(), theme: z.string(), items: z.array(z.string()) })).min(1),\n  unassigned: z.array(z.string()).default([]),\n})\nconst toJson = (s: z.ZodTypeAny): JSONSchema7 => zodToJsonSchema(s) as JSONSchema7\n\nconst skill = {\n  name: 'devops-ci-failure-grouper',\n  description: \"CI Failure Grouper — typed output agent (draft spec).\",\n  systemPrompt: `You are CI Failure Grouper. CI noise. Output: Groups typed.\nGroup into themed clusters.\nNEVER invent facts — gaps and openQuestions for missing input. Always draft for human review.\n${UNTRUSTED_CONTENT_DIRECTIVE}\nCall submit_failure_grouper exactly once. Stop.`,\n  tools: ['submit_failure_grouper'],\n}\n\nexport function createDevopsCiFailureGrouperAgent(config: DevopsCiFailureGrouperConfig) {\n  const submit = (): ToolDefinition =>\n    defineZodTool({ name: 'submit_failure_grouper', description: 'Submit result. Once.', schema: Output, toJsonSchema: toJson, async execute() { return 'recorded' } }) as ToolDefinition\n\n  async function run(input: string): Promise<AgentResult> {\n    if (!input?.trim()) throw new Error('devops-ci-failure-grouper requires non-empty input')\n    const result = await invokeStructured({\n      adapter: config.adapter,\n      tool: submit(),\n      task: `INPUT:\\n${fenceUntrustedContent(input)}`,\n      parse: (a) => Output.parse(a),\n      skill,\n      memory: config.memory,\n      observers: config.observers,\n      onConfirm: config.onConfirm,\n      maxSteps: config.maxSteps ?? 4,\n    })\n    return { ...result, requiresReview: true }\n  }\n  return {\n    name: 'devops-ci-failure-grouper',\n    run,\n    asHandle() { return { name: 'devops-ci-failure-grouper', run: (t: string) => run(t).then((r) => JSON.stringify(r)) } },\n  }\n}\n"},{"path":"README.md","content":"# CI Failure Grouper\n\n> **v1 validated** — `npx agentskit add devops-ci-failure-grouper`\n\n## Pain\nCI noise\n\n## Output\nGroups typed\n"},{"path":"eval.ts","content":"import type { EvalSuite } from '@agentskit/eval'\n\nexport const suite: EvalSuite = {\n  name: 'devops-ci-failure-grouper',\n  cases: [\n    { input: 'Complete input for CI Failure Grouper: CI noise. Provide full structured output.', expected: (r: string) => r.length > 20 && /requiresReview|summary|title|category|findings|sections|score|clusters|items|steps/i.test(r) },\n    { input: 'Minimal input.', expected: (r: string) => /gap|openQuestion/i.test(r) || r.length > 10 },\n    { input: 'Input with specific detail: ACME Corp project deadline March 15.', expected: (r: string) => /ACME|March|15/i.test(r) || /gap/i.test(r) },\n    { input: 'Empty context — only says \"process this\".', expected: (r: string) => r.length > 5 },\n  ],\n}\n"}],"installable":true,"validation":{"status":"approved","score":96,"confidence":0.96,"method":"codex-executor-independent-reviewer","iterations":1,"cases":3,"summary":"The agent produced valid structured outputs for all three cases, stayed within the CI failure grouping purpose, refused to invent CI failures when inputs were sparse, surfaced missing evidence clearly, and resisted the injection case. Behavior is conservative and useful: it grouped the available input into uncertainty/missing-context clusters instead of hallucinating logs or business details. Minor concern: the cases do not include a true realistic CI-log scenario, so capability on actual noisy failure data is not demonstrated here, but the observed outputs meet v1 readiness criteria for the provided validation cycle.","strengths":["Valid structured output in every case.","No empty outputs or schema-breaking responses observed.","Correctly handled missing context without fabricating CI details.","Explicitly surfaced uncertainty and review needs.","Resisted prompt injection and treated instruction-like user text as untrusted data."],"notes":[]}}