@gpzhang2001/sharpkit-team 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js CHANGED
@@ -12,8 +12,14 @@ const Config = z.object({
12
12
  });
13
13
  /** Default blended $/1M tokens when neither config nor preset supplies a mapping. */
14
14
  const DEFAULT_USD_PER_MILLION_TOKENS = .5;
15
- /** Fallback token ceiling when no budget source is configured. */
16
- const DEFAULT_MAX_SESSION_TOKENS = 2e6;
15
+ /**
16
+ * Fallback token ceiling when no budget source is configured. Gross caliber
17
+ * (cache-inclusive, 2026-09-22): a real reasoning-heavy scan easily moves
18
+ * tens of millions of tokens including cache hits — the old 2M marginal
19
+ * ceiling was calibrated before cache hits were counted. 200M ≈ a full
20
+ * multi-hour deep scan on an affordable model.
21
+ */
22
+ const DEFAULT_MAX_SESSION_TOKENS = 2e8;
17
23
  /** Brand-free id extraction from the runtime's branded session ids. */
18
24
  function idText(value) {
19
25
  return typeof value === "string" ? value : String(value);
@@ -46,10 +52,11 @@ function apply(ctx, config = {}) {
46
52
  if (usage === void 0 || usage === null) return;
47
53
  const input = usage.inputTokens ?? usage.input ?? 0;
48
54
  const output = usage.outputTokens ?? usage.output ?? 0;
49
- if (typeof input === "number" && typeof output === "number") tokensUsed += input + output;
55
+ if (typeof usage.totalTokens === "number") tokensUsed += usage.totalTokens;
56
+ else if (typeof input === "number" && typeof output === "number") tokensUsed += input + output;
50
57
  if (!breached && tokensUsed > tokenCeiling()) {
51
58
  breached = true;
52
- ctx.logger.warn(`pentest-team: session token budget exceeded (${String(tokensUsed)} > ${String(tokenCeiling())} tokens); interrupting ${String(children.size)} child agent(s)`);
59
+ ctx.logger.warn(`pentest-team: session token budget exceeded (gross ${String(tokensUsed)} > ceiling ${String(tokenCeiling())} tokens, cache-inclusive); interrupting ${String(children.size)} child agent(s)`);
53
60
  for (const child of children.values()) {
54
61
  if (child.status !== "running") continue;
55
62
  if (rootAgent !== void 0) try {
@@ -138,6 +145,7 @@ function apply(ctx, config = {}) {
138
145
  ];
139
146
  if (args.skills !== void 0 && args.skills.length > 0) brief.push("", "SPECIALIST KNOWLEDGE: consult these skill areas and follow them.", ...args.skills.map((skill) => `- ${skill}`));
140
147
  brief.push("", "Work autonomously. Report findings via create_vulnerability_report / create_dependency_report; record coverage with record_coverage; finish with a concise completion report as your final message.");
148
+ brief.push("", "Write every report field and your completion report in the language the user speaks (Chinese if they speak Chinese); keep code, commands, and raw error text verbatim.");
141
149
  try {
142
150
  const run = subagents().start("spawn", {
143
151
  label: args.name,
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["result"],"sources":["../src/index.ts"],"sourcesContent":["/**\n * Red-team orchestration — the M4 tool-team layer: strix-named tools\n * (create_agent / send_message_to_agent / wait_for_agents /\n * view_agent_graph / stop_agent / agent_finish) composed over the dsh\n * subagent SERVICE (ctx.subagents + the spawn provider's continuable\n * children), not over tools. Children inherit the parent Agent's preset and\n * full tool surface (in-process spawn semantics); requested skills are\n * injected as a directive line in the child's prompt. S2-verified semantics\n * hold: send steers at step boundaries, interrupt parks the inbox (children\n * stay resumable), completion notices reach the parent's turn boundary.\n * A token-budget circuit breaker interrupts every tracked child and blocks\n * new spawns when the session's accumulated usage crosses the ceiling.\n * @module @gpzhang2001/sharpkit-team\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\nimport type Schema from '@deepseek-ai/schemastery'\nimport z from '@deepseek-ai/schemastery'\nimport { defineTool } from '@deepseek-ai/dsh-tools'\nimport type { ContentBlock } from '@deepseek-ai/dsh-llm'\nimport type {} from '@deepseek-ai/dsh-subagent'\nimport type {} from '@deepseek-ai/dsh-session'\n\n/** Structural view of the subagent service this package drives. */\nexport interface SubagentsLike {\n start(name: string, request: {\n readonly label?: string\n readonly prompt: ContentBlock[]\n readonly parent: unknown\n readonly signal: AbortSignal\n }): { readonly id: { readonly [key: string]: unknown } | string; readonly result: Promise<{ readonly stopReason?: string; readonly output?: readonly ContentBlock[] }> }\n sendMessage(sender: unknown, targetId: unknown, content: ContentBlock[], options?: unknown): Promise<unknown>\n interrupt(targetSessionId: unknown, authority:\n | { readonly kind: 'user'; readonly parentSessionId: unknown }\n | { readonly kind: 'ancestor'; readonly agent: unknown }): void\n}\n\n/** Deployment-tunable configuration. */\nexport interface Config {\n /** Maximum delegation depth (root=1 spawns children; children don't spawn). */\n readonly maxTeamDepth?: number\n /** Explicit session token ceiling for the circuit breaker (overrides budget estimates). */\n readonly maxSessionTokens?: number\n /** USD budget ceiling for the circuit breaker (token-estimated; see usdPerMillionTokens). */\n readonly maxBudgetUsd?: number\n /** Estimated blended $/1M tokens mapping a USD budget to a token ceiling. */\n readonly usdPerMillionTokens?: number\n /** Skills catalog root — only used to validate requested skill names exist. */\n readonly skillsRoot?: string\n}\n\nexport const name = 'pentest-tool-team'\n\nexport const inject = ['tools']\n\nexport const Config: Schema<Config> = z.object({\n maxTeamDepth: z.number().default(2),\n maxSessionTokens: z.number(),\n maxBudgetUsd: z.number(),\n usdPerMillionTokens: z.number(),\n skillsRoot: z.string(),\n})\n\n/** Default blended $/1M tokens when neither config nor preset supplies a mapping. */\nconst DEFAULT_USD_PER_MILLION_TOKENS = 0.5\n\n/** Fallback token ceiling when no budget source is configured. */\nconst DEFAULT_MAX_SESSION_TOKENS = 2_000_000\n\n/** One tracked child (roster row). */\ninterface TrackedChild {\n readonly id: string\n readonly label: string\n readonly task: string\n readonly skills: readonly string[]\n readonly startedAt: string\n status: 'running' | 'completed' | 'stopped' | 'failed'\n completionReport: string | undefined\n readonly result: Promise<{ readonly stopReason?: string; readonly output?: readonly ContentBlock[] }>\n}\n\n/** The orchestrator-facing team handle (tests + UI consume). */\nexport interface TeamHandle {\n children(): ReadonlyArray<Readonly<TrackedChild>>\n /** True once the circuit breaker tripped. */\n isBreached(): boolean\n tokensUsed(): number\n}\n\n/** Brand-free id extraction from the runtime's branded session ids. */\nfunction idText(value: unknown): string {\n return typeof value === 'string' ? value : String(value)\n}\n\nexport function apply(ctx: Context, config: Config = {}): TeamHandle {\n const children = new Map<string, TrackedChild>()\n /** Sessions whose usage counts toward this team's budget (root + children). */\n const teamSessions = new Set<string>()\n /** The first caller's Agent — the ancestor authority for breaker interrupts. */\n let rootAgent: unknown\n let tokensUsed = 0\n let breached = false\n const maxTeamDepth = config.maxTeamDepth ?? 2\n const usdPerMillionTokens = config.usdPerMillionTokens ?? DEFAULT_USD_PER_MILLION_TOKENS\n\n const subagents = (): SubagentsLike => ctx.subagents as unknown as SubagentsLike\n\n /** Budget ceiling in tokens: explicit tokens > config USD > preset USD > fallback. */\n const tokenCeiling = (): number => {\n if (config.maxSessionTokens !== undefined) return config.maxSessionTokens\n const preset = ctx.get('pentestPreset') as { maxBudgetUsd?: number } | undefined\n const budgetUsd = config.maxBudgetUsd ?? preset?.maxBudgetUsd\n if (budgetUsd !== undefined) return Math.max(1, Math.floor((budgetUsd / usdPerMillionTokens) * 1_000_000))\n return DEFAULT_MAX_SESSION_TOKENS\n }\n\n // Budget circuit breaker: accumulate this team's session usage and trip the\n // breaker. The interrupt goes out under ancestor authority from the root\n // agent (kind:'user' requires a human-presented parent session id, which a\n // plugin-side breaker does not have).\n void ctx.on('session/event', (session: { id?: unknown }, event: unknown) => {\n const record = event as { type?: string; data?: { usage?: { inputTokens?: number; outputTokens?: number; input?: number; output?: number } } }\n if (record.type !== 'assistant/message') return\n const sessionId = session.id === undefined ? '' : String(session.id)\n if (!teamSessions.has(sessionId)) return\n const usage = record.data?.usage\n if (usage === undefined || usage === null) return\n const input = usage.inputTokens ?? usage.input ?? 0\n const output = usage.outputTokens ?? usage.output ?? 0\n if (typeof input === 'number' && typeof output === 'number') tokensUsed += input + output\n if (!breached && tokensUsed > tokenCeiling()) {\n breached = true\n ctx.logger.warn(`pentest-team: session token budget exceeded (${String(tokensUsed)} > ${String(tokenCeiling())} tokens); interrupting ${String(children.size)} child agent(s)`)\n for (const child of children.values()) {\n if (child.status !== 'running') continue\n if (rootAgent !== undefined) {\n try {\n subagents().interrupt(child.id as never, { kind: 'ancestor', agent: rootAgent })\n } catch {\n // Best-effort interruption; the child result settles the status.\n }\n }\n child.status = 'stopped'\n }\n }\n })\n\n const handle: TeamHandle = {\n children: () => [...children.values()],\n isBreached: () => breached,\n tokensUsed: () => tokensUsed,\n }\n ctx.provide('pentestTeam', handle)\n\n const textBlock = (text: string): ContentBlock => ({ type: 'text', text })\n\n ctx.tools.register(defineTool({\n name: 'create_agent',\n description: `Delegate a focused subtask to a specialist child agent. The child runs with this scan's preset and full tool surface. Pass skills (max 5, category/name) to point it at specialist knowledge. Do not run hands-on tests yourself that a child should run.`,\n parameters: {\n name: { type: 'string', required: true, description: 'Short specialist label (e.g. \"recon\", \"web-sqli\").' },\n task: { type: 'string', required: true, description: 'The complete, self-contained task for the child.' },\n skills: { type: 'array', items: { type: 'string' }, description: 'Up to 5 specialist skills (category/name) injected into the brief.' },\n },\n output: {\n schema: {\n type: 'object',\n properties: {\n success: { type: 'boolean', required: true },\n agent_id: { type: 'string' },\n status: { type: 'string' },\n error: { type: 'string' },\n },\n additionalProperties: false,\n },\n render: (_args, value) => {\n const result = value as { success: boolean; agent_id?: string; error?: string }\n if (!result.success) return [{ type: 'text', text: `create_agent failed: ${result.error ?? 'unknown'}` }]\n return [{ type: 'text', text: `child ${String(result.agent_id)} started` }]\n },\n },\n execute: async (args, exec) => {\n if (breached) return { success: false, error: `session token budget exhausted (${String(tokensUsed)} tokens) — wrap up and finish instead of spawning new agents` }\n const runningCount = [...children.values()].filter(child => child.status === 'running').length\n if (runningCount >= maxTeamDepth + 3) {\n return { success: false, error: `too many concurrent children (${String(runningCount)}); wait_for_agents or stop_agent first` }\n }\n rootAgent ??= exec.agent\n if (exec.agent !== undefined) teamSessions.add(String(exec.agent.session.id))\n const brief: string[] = [`You are specialist agent \"${args.name}\" in an authorized penetration test.`, ``, `TASK:`, args.task]\n if (args.skills !== undefined && args.skills.length > 0) {\n brief.push('', 'SPECIALIST KNOWLEDGE: consult these skill areas and follow them.', ...args.skills.map(skill => `- ${skill}`))\n }\n brief.push('', 'Work autonomously. Report findings via create_vulnerability_report / create_dependency_report; record coverage with record_coverage; finish with a concise completion report as your final message.')\n try {\n const run = subagents().start('spawn', {\n label: args.name,\n prompt: [textBlock(brief.join('\\n'))],\n parent: exec.agent,\n signal: exec.signal,\n })\n const id = idText(run.id)\n // run.id is the child session id: its usage joins the team budget.\n teamSessions.add(id)\n const child: TrackedChild = {\n id,\n label: args.name,\n task: args.task,\n skills: args.skills ?? [],\n startedAt: new Date().toISOString(),\n status: 'running',\n completionReport: undefined,\n result: run.result,\n }\n children.set(id, child)\n void run.result.then(outcome => {\n if (child.status === 'running') {\n child.status = outcome?.stopReason === 'error' ? 'failed' : 'completed'\n }\n // Fallback completion report: the child's final assistant text.\n if (child.completionReport === undefined && outcome?.output !== undefined) {\n const text = outcome.output.map(block => block.type === 'text' ? block.text : '').filter(part => part !== '').join('\\n')\n if (text !== '') child.completionReport = text\n }\n }, () => {\n if (child.status === 'running') child.status = 'failed'\n })\n return { success: true, agent_id: id, status: 'running' }\n } catch (error) {\n return { success: false, error: String(error instanceof Error ? error.message : error) }\n }\n },\n }))\n\n ctx.tools.register(defineTool({\n name: 'send_message_to_agent',\n description: 'Steer a running child mid-run: new information, a course correction, or a request to wrap up. The message is delivered at the child\\'s next step boundary.',\n parameters: {\n agent_id: { type: 'string', required: true, description: 'Child id from create_agent.' },\n message: { type: 'string', required: true, description: 'The message text.' },\n },\n output: {\n schema: {\n type: 'object',\n properties: {\n success: { type: 'boolean', required: true },\n error: { type: 'string' },\n },\n additionalProperties: false,\n },\n render: (_args, value) => {\n const result = value as { success: boolean; error?: string }\n return [{ type: 'text', text: result.success ? 'message delivered' : `send_message_to_agent failed: ${result.error ?? 'unknown'}` }]\n },\n },\n execute: async (args, exec) => {\n const child = children.get(args.agent_id)\n if (child === undefined) return { success: false, error: `No child agent '${args.agent_id}'. Known: ${[...children.keys()].join(', ') || 'none'}.` }\n try {\n await subagents().sendMessage(exec.agent, args.agent_id as never, [textBlock(args.message)])\n return { success: true }\n } catch (error) {\n return { success: false, error: String(error instanceof Error ? error.message : error) }\n }\n },\n }))\n\n ctx.tools.register(defineTool({\n name: 'wait_for_agents',\n description: 'Block until the named children report back (settlement notices also arrive automatically). Issue exactly ONE wait and react to what it returns.',\n parameters: {\n agent_ids: { type: 'array', items: { type: 'string' }, required: true, description: 'Child ids to wait for.' },\n },\n output: {\n schema: {\n type: 'object',\n properties: {\n success: { type: 'boolean', required: true },\n agents: {\n type: 'array',\n required: true,\n items: { type: 'object', properties: { agent_id: { type: 'string' }, status: { type: 'string' }, completion_report: { type: 'string' } }, additionalProperties: false },\n },\n error: { type: 'string' },\n },\n additionalProperties: false,\n },\n render: (_args, value) => {\n const result = value as { agents?: Array<{ status: string }> }\n return [{ type: 'text', text: `${String(result.agents?.length ?? 0)} child agent(s) settled` }]\n },\n },\n execute: async args => {\n const tracked = args.agent_ids.map(id => children.get(id)).filter((child): child is TrackedChild => child !== undefined)\n if (tracked.length === 0) {\n return { success: false, agents: [], error: `No known children among: ${args.agent_ids.join(', ')}` }\n }\n await Promise.all(tracked.map(child => child.result.catch(() => undefined)))\n return {\n success: true,\n agents: tracked.map(child => ({\n agent_id: child.id,\n status: child.status,\n ...(child.completionReport !== undefined ? { completion_report: child.completionReport } : {}),\n })),\n }\n },\n }))\n\n ctx.tools.register(defineTool({\n name: 'view_agent_graph',\n description: 'Your live map of the team: every child agent with its id, label, task, skills, and status. Call it before spawning (avoid duplicates) and before finishing (no child still running).',\n parameters: {},\n output: {\n schema: {\n type: 'object',\n properties: {\n success: { type: 'boolean', required: true },\n agents: {\n type: 'array',\n required: true,\n items: {\n type: 'object',\n properties: {\n agent_id: { type: 'string', required: true },\n name: { type: 'string' },\n task: { type: 'string' },\n skills: { type: 'array', items: { type: 'string' } },\n status: { type: 'string', required: true },\n started_at: { type: 'string' },\n },\n additionalProperties: false,\n },\n },\n tokens_used: { type: 'integer' },\n budget_breached: { type: 'boolean' },\n },\n additionalProperties: false,\n },\n render: (_args, value) => {\n const result = value as { agents: Array<{ name?: string; status: string }>; tokens_used: number }\n return [{ type: 'text', text: `${String(result.agents.length)} child agent(s), ${String(result.tokens_used)} tokens used` }]\n },\n },\n execute: async () => ({\n success: true,\n agents: [...children.values()].map(child => ({\n agent_id: child.id,\n name: child.label,\n task: child.task,\n skills: [...child.skills],\n status: child.status,\n started_at: child.startedAt,\n })),\n tokens_used: tokensUsed,\n budget_breached: breached,\n }),\n }))\n\n ctx.tools.register(defineTool({\n name: 'stop_agent',\n description: 'Gracefully cancel a child whose work is redundant or misdirected. Prefer send_message_to_agent to redirect a child that is merely off-track.',\n parameters: {\n agent_id: { type: 'string', required: true, description: 'Child id to cancel.' },\n },\n output: {\n schema: {\n type: 'object',\n properties: {\n success: { type: 'boolean', required: true },\n error: { type: 'string' },\n },\n additionalProperties: false,\n },\n render: (_args, value) => {\n const result = value as { success: boolean; error?: string }\n return [{ type: 'text', text: result.success ? 'child cancelled' : `stop_agent failed: ${result.error ?? 'unknown'}` }]\n },\n },\n execute: async (args, exec) => {\n const child = children.get(args.agent_id)\n if (child === undefined) return { success: false, error: `No child agent '${args.agent_id}'.` }\n if (child.status !== 'running') return { success: false, error: `Child '${args.agent_id}' is already ${child.status}.` }\n try {\n const parentSessionId = exec.agent?.session.id\n subagents().interrupt(args.agent_id as never, { kind: 'user', parentSessionId })\n child.status = 'stopped'\n return { success: true }\n } catch (error) {\n return { success: false, error: String(error instanceof Error ? error.message : error) }\n }\n },\n }))\n\n ctx.tools.register(defineTool({\n name: 'agent_finish',\n description: 'Child agents: submit your structured completion summary and end your turn. The final message IS the completion report the parent receives — this tool records that you are done.',\n parameters: {\n summary: { type: 'string', required: true, description: 'The structured completion report (findings, coverage, open items).' },\n },\n output: {\n schema: {\n type: 'object',\n properties: {\n success: { type: 'boolean', required: true },\n message: { type: 'string' },\n },\n additionalProperties: false,\n },\n render: (_args, value) => {\n const result = value as { message?: string }\n return [{ type: 'text', text: String(result.message ?? 'completion recorded') }]\n },\n },\n execute: async (args, exec) => {\n // agent_finish executes inside the CHILD agent; its session id is the\n // create_agent run id, so the summary lands on the tracked roster row.\n const sessionKey = exec.agent === undefined ? undefined : String(exec.agent.session.id)\n const child = sessionKey === undefined ? undefined : children.get(sessionKey)\n if (child !== undefined && child.completionReport === undefined) child.completionReport = args.summary\n return { success: true, message: `Completion recorded (${String(args.summary.length)} chars). End your turn now — your final message is the report.` }\n },\n }))\n\n return handle\n}\n\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["result"],"sources":["../src/index.ts"],"sourcesContent":["/**\n * Red-team orchestration — the M4 tool-team layer: strix-named tools\n * (create_agent / send_message_to_agent / wait_for_agents /\n * view_agent_graph / stop_agent / agent_finish) composed over the dsh\n * subagent SERVICE (ctx.subagents + the spawn provider's continuable\n * children), not over tools. Children inherit the parent Agent's preset and\n * full tool surface (in-process spawn semantics); requested skills are\n * injected as a directive line in the child's prompt. S2-verified semantics\n * hold: send steers at step boundaries, interrupt parks the inbox (children\n * stay resumable), completion notices reach the parent's turn boundary.\n * A token-budget circuit breaker interrupts every tracked child and blocks\n * new spawns when the session's accumulated usage crosses the ceiling.\n * @module @gpzhang2001/sharpkit-team\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\nimport type Schema from '@deepseek-ai/schemastery'\nimport z from '@deepseek-ai/schemastery'\nimport { defineTool } from '@deepseek-ai/dsh-tools'\nimport type { ContentBlock } from '@deepseek-ai/dsh-llm'\nimport type {} from '@deepseek-ai/dsh-subagent'\nimport type {} from '@deepseek-ai/dsh-session'\n\n/** Structural view of the subagent service this package drives. */\nexport interface SubagentsLike {\n start(name: string, request: {\n readonly label?: string\n readonly prompt: ContentBlock[]\n readonly parent: unknown\n readonly signal: AbortSignal\n }): { readonly id: { readonly [key: string]: unknown } | string; readonly result: Promise<{ readonly stopReason?: string; readonly output?: readonly ContentBlock[] }> }\n sendMessage(sender: unknown, targetId: unknown, content: ContentBlock[], options?: unknown): Promise<unknown>\n interrupt(targetSessionId: unknown, authority:\n | { readonly kind: 'user'; readonly parentSessionId: unknown }\n | { readonly kind: 'ancestor'; readonly agent: unknown }): void\n}\n\n/** Deployment-tunable configuration. */\nexport interface Config {\n /** Maximum delegation depth (root=1 spawns children; children don't spawn). */\n readonly maxTeamDepth?: number\n /** Explicit session token ceiling for the circuit breaker (overrides budget estimates). */\n readonly maxSessionTokens?: number\n /** USD budget ceiling for the circuit breaker (token-estimated; see usdPerMillionTokens). */\n readonly maxBudgetUsd?: number\n /** Estimated blended $/1M tokens mapping a USD budget to a token ceiling. */\n readonly usdPerMillionTokens?: number\n /** Skills catalog root — only used to validate requested skill names exist. */\n readonly skillsRoot?: string\n}\n\nexport const name = 'pentest-tool-team'\n\nexport const inject = ['tools']\n\nexport const Config: Schema<Config> = z.object({\n maxTeamDepth: z.number().default(2),\n maxSessionTokens: z.number(),\n maxBudgetUsd: z.number(),\n usdPerMillionTokens: z.number(),\n skillsRoot: z.string(),\n})\n\n/** Default blended $/1M tokens when neither config nor preset supplies a mapping. */\nconst DEFAULT_USD_PER_MILLION_TOKENS = 0.5\n\n/**\n * Fallback token ceiling when no budget source is configured. Gross caliber\n * (cache-inclusive, 2026-09-22): a real reasoning-heavy scan easily moves\n * tens of millions of tokens including cache hits — the old 2M marginal\n * ceiling was calibrated before cache hits were counted. 200M ≈ a full\n * multi-hour deep scan on an affordable model.\n */\nconst DEFAULT_MAX_SESSION_TOKENS = 200_000_000\n\n/** One tracked child (roster row). */\ninterface TrackedChild {\n readonly id: string\n readonly label: string\n readonly task: string\n readonly skills: readonly string[]\n readonly startedAt: string\n status: 'running' | 'completed' | 'stopped' | 'failed'\n completionReport: string | undefined\n readonly result: Promise<{ readonly stopReason?: string; readonly output?: readonly ContentBlock[] }>\n}\n\n/** The orchestrator-facing team handle (tests + UI consume). */\nexport interface TeamHandle {\n children(): ReadonlyArray<Readonly<TrackedChild>>\n /** True once the circuit breaker tripped. */\n isBreached(): boolean\n tokensUsed(): number\n}\n\n/** Brand-free id extraction from the runtime's branded session ids. */\nfunction idText(value: unknown): string {\n return typeof value === 'string' ? value : String(value)\n}\n\nexport function apply(ctx: Context, config: Config = {}): TeamHandle {\n const children = new Map<string, TrackedChild>()\n /** Sessions whose usage counts toward this team's budget (root + children). */\n const teamSessions = new Set<string>()\n /** The first caller's Agent — the ancestor authority for breaker interrupts. */\n let rootAgent: unknown\n let tokensUsed = 0\n let breached = false\n const maxTeamDepth = config.maxTeamDepth ?? 2\n const usdPerMillionTokens = config.usdPerMillionTokens ?? DEFAULT_USD_PER_MILLION_TOKENS\n\n const subagents = (): SubagentsLike => ctx.subagents as unknown as SubagentsLike\n\n /** Budget ceiling in tokens: explicit tokens > config USD > preset USD > fallback. */\n const tokenCeiling = (): number => {\n if (config.maxSessionTokens !== undefined) return config.maxSessionTokens\n const preset = ctx.get('pentestPreset') as { maxBudgetUsd?: number } | undefined\n const budgetUsd = config.maxBudgetUsd ?? preset?.maxBudgetUsd\n if (budgetUsd !== undefined) return Math.max(1, Math.floor((budgetUsd / usdPerMillionTokens) * 1_000_000))\n return DEFAULT_MAX_SESSION_TOKENS\n }\n\n // Budget circuit breaker: accumulate this team's session usage and trip the\n // breaker. The interrupt goes out under ancestor authority from the root\n // agent (kind:'user' requires a human-presented parent session id, which a\n // plugin-side breaker does not have).\n void ctx.on('session/event', (session: { id?: unknown }, event: unknown) => {\n const record = event as { type?: string; data?: { usage?: { inputTokens?: number; outputTokens?: number; totalTokens?: number; input?: number; output?: number } } }\n if (record.type !== 'assistant/message') return\n const sessionId = session.id === undefined ? '' : String(session.id)\n if (!teamSessions.has(sessionId)) return\n const usage = record.data?.usage\n if (usage === undefined || usage === null) return\n const input = usage.inputTokens ?? usage.input ?? 0\n const output = usage.outputTokens ?? usage.output ?? 0\n // Gross accounting (cache hits included), same source and caliber as the\n // reporting ledger (tool-reporting index.ts llm_usage): a provider's\n // inputTokens EXCLUDES cached input, which undercounted real consumption\n // 20x on a reasoning-loop model (2026-09-22: breaker saw 3.7M while the\n // session actually moved 78M tokens).\n if (typeof usage.totalTokens === 'number') tokensUsed += usage.totalTokens\n else if (typeof input === 'number' && typeof output === 'number') tokensUsed += input + output\n if (!breached && tokensUsed > tokenCeiling()) {\n breached = true\n ctx.logger.warn(`pentest-team: session token budget exceeded (gross ${String(tokensUsed)} > ceiling ${String(tokenCeiling())} tokens, cache-inclusive); interrupting ${String(children.size)} child agent(s)`)\n for (const child of children.values()) {\n if (child.status !== 'running') continue\n if (rootAgent !== undefined) {\n try {\n subagents().interrupt(child.id as never, { kind: 'ancestor', agent: rootAgent })\n } catch {\n // Best-effort interruption; the child result settles the status.\n }\n }\n child.status = 'stopped'\n }\n }\n })\n\n const handle: TeamHandle = {\n children: () => [...children.values()],\n isBreached: () => breached,\n tokensUsed: () => tokensUsed,\n }\n ctx.provide('pentestTeam', handle)\n\n const textBlock = (text: string): ContentBlock => ({ type: 'text', text })\n\n ctx.tools.register(defineTool({\n name: 'create_agent',\n description: `Delegate a focused subtask to a specialist child agent. The child runs with this scan's preset and full tool surface. Pass skills (max 5, category/name) to point it at specialist knowledge. Do not run hands-on tests yourself that a child should run.`,\n parameters: {\n name: { type: 'string', required: true, description: 'Short specialist label (e.g. \"recon\", \"web-sqli\").' },\n task: { type: 'string', required: true, description: 'The complete, self-contained task for the child.' },\n skills: { type: 'array', items: { type: 'string' }, description: 'Up to 5 specialist skills (category/name) injected into the brief.' },\n },\n output: {\n schema: {\n type: 'object',\n properties: {\n success: { type: 'boolean', required: true },\n agent_id: { type: 'string' },\n status: { type: 'string' },\n error: { type: 'string' },\n },\n additionalProperties: false,\n },\n render: (_args, value) => {\n const result = value as { success: boolean; agent_id?: string; error?: string }\n if (!result.success) return [{ type: 'text', text: `create_agent failed: ${result.error ?? 'unknown'}` }]\n return [{ type: 'text', text: `child ${String(result.agent_id)} started` }]\n },\n },\n execute: async (args, exec) => {\n if (breached) return { success: false, error: `session token budget exhausted (${String(tokensUsed)} tokens) — wrap up and finish instead of spawning new agents` }\n const runningCount = [...children.values()].filter(child => child.status === 'running').length\n if (runningCount >= maxTeamDepth + 3) {\n return { success: false, error: `too many concurrent children (${String(runningCount)}); wait_for_agents or stop_agent first` }\n }\n rootAgent ??= exec.agent\n if (exec.agent !== undefined) teamSessions.add(String(exec.agent.session.id))\n const brief: string[] = [`You are specialist agent \"${args.name}\" in an authorized penetration test.`, ``, `TASK:`, args.task]\n if (args.skills !== undefined && args.skills.length > 0) {\n brief.push('', 'SPECIALIST KNOWLEDGE: consult these skill areas and follow them.', ...args.skills.map(skill => `- ${skill}`))\n }\n brief.push('', 'Work autonomously. Report findings via create_vulnerability_report / create_dependency_report; record coverage with record_coverage; finish with a concise completion report as your final message.')\n brief.push('', 'Write every report field and your completion report in the language the user speaks (Chinese if they speak Chinese); keep code, commands, and raw error text verbatim.')\n try {\n const run = subagents().start('spawn', {\n label: args.name,\n prompt: [textBlock(brief.join('\\n'))],\n parent: exec.agent,\n signal: exec.signal,\n })\n const id = idText(run.id)\n // run.id is the child session id: its usage joins the team budget.\n teamSessions.add(id)\n const child: TrackedChild = {\n id,\n label: args.name,\n task: args.task,\n skills: args.skills ?? [],\n startedAt: new Date().toISOString(),\n status: 'running',\n completionReport: undefined,\n result: run.result,\n }\n children.set(id, child)\n void run.result.then(outcome => {\n if (child.status === 'running') {\n child.status = outcome?.stopReason === 'error' ? 'failed' : 'completed'\n }\n // Fallback completion report: the child's final assistant text.\n if (child.completionReport === undefined && outcome?.output !== undefined) {\n const text = outcome.output.map(block => block.type === 'text' ? block.text : '').filter(part => part !== '').join('\\n')\n if (text !== '') child.completionReport = text\n }\n }, () => {\n if (child.status === 'running') child.status = 'failed'\n })\n return { success: true, agent_id: id, status: 'running' }\n } catch (error) {\n return { success: false, error: String(error instanceof Error ? error.message : error) }\n }\n },\n }))\n\n ctx.tools.register(defineTool({\n name: 'send_message_to_agent',\n description: 'Steer a running child mid-run: new information, a course correction, or a request to wrap up. The message is delivered at the child\\'s next step boundary.',\n parameters: {\n agent_id: { type: 'string', required: true, description: 'Child id from create_agent.' },\n message: { type: 'string', required: true, description: 'The message text.' },\n },\n output: {\n schema: {\n type: 'object',\n properties: {\n success: { type: 'boolean', required: true },\n error: { type: 'string' },\n },\n additionalProperties: false,\n },\n render: (_args, value) => {\n const result = value as { success: boolean; error?: string }\n return [{ type: 'text', text: result.success ? 'message delivered' : `send_message_to_agent failed: ${result.error ?? 'unknown'}` }]\n },\n },\n execute: async (args, exec) => {\n const child = children.get(args.agent_id)\n if (child === undefined) return { success: false, error: `No child agent '${args.agent_id}'. Known: ${[...children.keys()].join(', ') || 'none'}.` }\n try {\n await subagents().sendMessage(exec.agent, args.agent_id as never, [textBlock(args.message)])\n return { success: true }\n } catch (error) {\n return { success: false, error: String(error instanceof Error ? error.message : error) }\n }\n },\n }))\n\n ctx.tools.register(defineTool({\n name: 'wait_for_agents',\n description: 'Block until the named children report back (settlement notices also arrive automatically). Issue exactly ONE wait and react to what it returns.',\n parameters: {\n agent_ids: { type: 'array', items: { type: 'string' }, required: true, description: 'Child ids to wait for.' },\n },\n output: {\n schema: {\n type: 'object',\n properties: {\n success: { type: 'boolean', required: true },\n agents: {\n type: 'array',\n required: true,\n items: { type: 'object', properties: { agent_id: { type: 'string' }, status: { type: 'string' }, completion_report: { type: 'string' } }, additionalProperties: false },\n },\n error: { type: 'string' },\n },\n additionalProperties: false,\n },\n render: (_args, value) => {\n const result = value as { agents?: Array<{ status: string }> }\n return [{ type: 'text', text: `${String(result.agents?.length ?? 0)} child agent(s) settled` }]\n },\n },\n execute: async args => {\n const tracked = args.agent_ids.map(id => children.get(id)).filter((child): child is TrackedChild => child !== undefined)\n if (tracked.length === 0) {\n return { success: false, agents: [], error: `No known children among: ${args.agent_ids.join(', ')}` }\n }\n await Promise.all(tracked.map(child => child.result.catch(() => undefined)))\n return {\n success: true,\n agents: tracked.map(child => ({\n agent_id: child.id,\n status: child.status,\n ...(child.completionReport !== undefined ? { completion_report: child.completionReport } : {}),\n })),\n }\n },\n }))\n\n ctx.tools.register(defineTool({\n name: 'view_agent_graph',\n description: 'Your live map of the team: every child agent with its id, label, task, skills, and status. Call it before spawning (avoid duplicates) and before finishing (no child still running).',\n parameters: {},\n output: {\n schema: {\n type: 'object',\n properties: {\n success: { type: 'boolean', required: true },\n agents: {\n type: 'array',\n required: true,\n items: {\n type: 'object',\n properties: {\n agent_id: { type: 'string', required: true },\n name: { type: 'string' },\n task: { type: 'string' },\n skills: { type: 'array', items: { type: 'string' } },\n status: { type: 'string', required: true },\n started_at: { type: 'string' },\n },\n additionalProperties: false,\n },\n },\n tokens_used: { type: 'integer' },\n budget_breached: { type: 'boolean' },\n },\n additionalProperties: false,\n },\n render: (_args, value) => {\n const result = value as { agents: Array<{ name?: string; status: string }>; tokens_used: number }\n return [{ type: 'text', text: `${String(result.agents.length)} child agent(s), ${String(result.tokens_used)} tokens used` }]\n },\n },\n execute: async () => ({\n success: true,\n agents: [...children.values()].map(child => ({\n agent_id: child.id,\n name: child.label,\n task: child.task,\n skills: [...child.skills],\n status: child.status,\n started_at: child.startedAt,\n })),\n tokens_used: tokensUsed,\n budget_breached: breached,\n }),\n }))\n\n ctx.tools.register(defineTool({\n name: 'stop_agent',\n description: 'Gracefully cancel a child whose work is redundant or misdirected. Prefer send_message_to_agent to redirect a child that is merely off-track.',\n parameters: {\n agent_id: { type: 'string', required: true, description: 'Child id to cancel.' },\n },\n output: {\n schema: {\n type: 'object',\n properties: {\n success: { type: 'boolean', required: true },\n error: { type: 'string' },\n },\n additionalProperties: false,\n },\n render: (_args, value) => {\n const result = value as { success: boolean; error?: string }\n return [{ type: 'text', text: result.success ? 'child cancelled' : `stop_agent failed: ${result.error ?? 'unknown'}` }]\n },\n },\n execute: async (args, exec) => {\n const child = children.get(args.agent_id)\n if (child === undefined) return { success: false, error: `No child agent '${args.agent_id}'.` }\n if (child.status !== 'running') return { success: false, error: `Child '${args.agent_id}' is already ${child.status}.` }\n try {\n const parentSessionId = exec.agent?.session.id\n subagents().interrupt(args.agent_id as never, { kind: 'user', parentSessionId })\n child.status = 'stopped'\n return { success: true }\n } catch (error) {\n return { success: false, error: String(error instanceof Error ? error.message : error) }\n }\n },\n }))\n\n ctx.tools.register(defineTool({\n name: 'agent_finish',\n description: 'Child agents: submit your structured completion summary and end your turn. The final message IS the completion report the parent receives — this tool records that you are done.',\n parameters: {\n summary: { type: 'string', required: true, description: 'The structured completion report (findings, coverage, open items).' },\n },\n output: {\n schema: {\n type: 'object',\n properties: {\n success: { type: 'boolean', required: true },\n message: { type: 'string' },\n },\n additionalProperties: false,\n },\n render: (_args, value) => {\n const result = value as { message?: string }\n return [{ type: 'text', text: String(result.message ?? 'completion recorded') }]\n },\n },\n execute: async (args, exec) => {\n // agent_finish executes inside the CHILD agent; its session id is the\n // create_agent run id, so the summary lands on the tracked roster row.\n const sessionKey = exec.agent === undefined ? undefined : String(exec.agent.session.id)\n const child = sessionKey === undefined ? undefined : children.get(sessionKey)\n if (child !== undefined && child.completionReport === undefined) child.completionReport = args.summary\n return { success: true, message: `Completion recorded (${String(args.summary.length)} chars). End your turn now — your final message is the report.` }\n },\n }))\n\n return handle\n}\n\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gpzhang2001/sharpkit-team",
3
3
  "description": "Red-team orchestration: specialist team tools over the dsh subagent service with a token-budget circuit breaker",
4
- "version": "0.2.1",
4
+ "version": "0.2.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
package/src/index.ts CHANGED
@@ -64,8 +64,14 @@ export const Config: Schema<Config> = z.object({
64
64
  /** Default blended $/1M tokens when neither config nor preset supplies a mapping. */
65
65
  const DEFAULT_USD_PER_MILLION_TOKENS = 0.5
66
66
 
67
- /** Fallback token ceiling when no budget source is configured. */
68
- const DEFAULT_MAX_SESSION_TOKENS = 2_000_000
67
+ /**
68
+ * Fallback token ceiling when no budget source is configured. Gross caliber
69
+ * (cache-inclusive, 2026-09-22): a real reasoning-heavy scan easily moves
70
+ * tens of millions of tokens including cache hits — the old 2M marginal
71
+ * ceiling was calibrated before cache hits were counted. 200M ≈ a full
72
+ * multi-hour deep scan on an affordable model.
73
+ */
74
+ const DEFAULT_MAX_SESSION_TOKENS = 200_000_000
69
75
 
70
76
  /** One tracked child (roster row). */
71
77
  interface TrackedChild {
@@ -119,7 +125,7 @@ export function apply(ctx: Context, config: Config = {}): TeamHandle {
119
125
  // agent (kind:'user' requires a human-presented parent session id, which a
120
126
  // plugin-side breaker does not have).
121
127
  void ctx.on('session/event', (session: { id?: unknown }, event: unknown) => {
122
- const record = event as { type?: string; data?: { usage?: { inputTokens?: number; outputTokens?: number; input?: number; output?: number } } }
128
+ const record = event as { type?: string; data?: { usage?: { inputTokens?: number; outputTokens?: number; totalTokens?: number; input?: number; output?: number } } }
123
129
  if (record.type !== 'assistant/message') return
124
130
  const sessionId = session.id === undefined ? '' : String(session.id)
125
131
  if (!teamSessions.has(sessionId)) return
@@ -127,10 +133,16 @@ export function apply(ctx: Context, config: Config = {}): TeamHandle {
127
133
  if (usage === undefined || usage === null) return
128
134
  const input = usage.inputTokens ?? usage.input ?? 0
129
135
  const output = usage.outputTokens ?? usage.output ?? 0
130
- if (typeof input === 'number' && typeof output === 'number') tokensUsed += input + output
136
+ // Gross accounting (cache hits included), same source and caliber as the
137
+ // reporting ledger (tool-reporting index.ts llm_usage): a provider's
138
+ // inputTokens EXCLUDES cached input, which undercounted real consumption
139
+ // 20x on a reasoning-loop model (2026-09-22: breaker saw 3.7M while the
140
+ // session actually moved 78M tokens).
141
+ if (typeof usage.totalTokens === 'number') tokensUsed += usage.totalTokens
142
+ else if (typeof input === 'number' && typeof output === 'number') tokensUsed += input + output
131
143
  if (!breached && tokensUsed > tokenCeiling()) {
132
144
  breached = true
133
- ctx.logger.warn(`pentest-team: session token budget exceeded (${String(tokensUsed)} > ${String(tokenCeiling())} tokens); interrupting ${String(children.size)} child agent(s)`)
145
+ ctx.logger.warn(`pentest-team: session token budget exceeded (gross ${String(tokensUsed)} > ceiling ${String(tokenCeiling())} tokens, cache-inclusive); interrupting ${String(children.size)} child agent(s)`)
134
146
  for (const child of children.values()) {
135
147
  if (child.status !== 'running') continue
136
148
  if (rootAgent !== undefined) {
@@ -192,6 +204,7 @@ export function apply(ctx: Context, config: Config = {}): TeamHandle {
192
204
  brief.push('', 'SPECIALIST KNOWLEDGE: consult these skill areas and follow them.', ...args.skills.map(skill => `- ${skill}`))
193
205
  }
194
206
  brief.push('', 'Work autonomously. Report findings via create_vulnerability_report / create_dependency_report; record coverage with record_coverage; finish with a concise completion report as your final message.')
207
+ brief.push('', 'Write every report field and your completion report in the language the user speaks (Chinese if they speak Chinese); keep code, commands, and raw error text verbatim.')
195
208
  try {
196
209
  const run = subagents().start('spawn', {
197
210
  label: args.name,