sync: update from private repo (dfadcd5f)
CI / build-and-test (push) Has been cancelled

This commit is contained in:
oss-sync
2026-06-23 06:38:48 +00:00
parent 6a2f2cc736
commit 29ccaf1e92
377 changed files with 31028 additions and 8994 deletions
+104
View File
@@ -0,0 +1,104 @@
/**
* RequestTool — META_TOOL for the tool-request mechanism.
*
* When an agent realises it needs a tool that this movement does not expose,
* it calls RequestTool({ name, reason }). The request is recorded so the gap
* becomes visible in the task detail and per-piece aggregation, letting the
* piece author add the tool to `allowed_tools` / `shared_tools`. This PR
* (recording infra) does NOT grant the tool — it records and guides. The
* inline approval/grant flow is layered on top in a later PR.
*
* Classification (recorded as `category`):
* - already_available → the tool IS exposed here; just call it (not recorded).
* - available_not_allowed (`requested`) → exists in the catalog but not in
* this movement → recorded as a genuine omission candidate.
* - unknown → not in the catalog (possible hallucination / capability gap).
*
* Plumbing: ToolContext carries `effectiveToolNames` (this movement's set),
* `knownToolNames` (full catalog, injected by the dispatcher), and
* `recordToolRequest` (bound to task/job/space by the worker).
*/
import { ToolDef } from '../../llm/openai-compat.js';
import type { ToolContext, ToolResult } from './core.js';
const REQUEST_TOOL_DEF: ToolDef = {
type: 'function',
function: {
name: 'RequestTool',
description:
'この movement に無いツールがどうしても必要なときに要求する。name と理由(reason)を渡すと記録され、ピース作者が allowed_tools / shared_tools に追加できる。要求しても今すぐ使えるようにはならない — 無しで進めるか、無理なら complete({status:"needs_user_input"}) でユーザーに依頼すること。詳細は ReadToolDoc({ name: "RequestTool" })。',
parameters: {
type: 'object',
properties: {
name: { type: 'string', description: '必要なツール名(例: WebSearch, Bash)。' },
reason: { type: 'string', description: 'なぜそのツールが必要か(具体的に)。' },
},
required: ['name', 'reason'],
},
},
};
export const TOOL_DEFS: Record<string, ToolDef> = {
RequestTool: REQUEST_TOOL_DEF,
};
export async function executeTool(
name: string,
input: Record<string, unknown>,
ctx: ToolContext,
): Promise<ToolResult | null> {
if (name !== 'RequestTool') return null;
const toolName = typeof input['name'] === 'string' ? input['name'].trim() : '';
const reason = typeof input['reason'] === 'string' ? input['reason'].trim() : '';
if (!toolName) return { output: 'RequestTool: name は必須です。', isError: true };
if (!reason) return { output: 'RequestTool: reason(なぜ必要か)は必須です。', isError: true };
// Already available in THIS movement → nothing to record, just tell it to call.
const effective = ctx.effectiveToolNames ?? [];
if (effective.includes(toolName)) {
return {
output: `"${toolName}" はこの movement で既に利用可能です。そのまま呼び出してください。`,
isError: false,
};
}
// Classify against the full catalog. MCP tools (mcp__*) can't be cheaply
// enumerated, so treat them as "exists but not allowed here".
const known = ctx.knownToolNames ?? [];
const isMcp = toolName.startsWith('mcp__');
const category: 'requested' | 'unknown' = known.includes(toolName) || isMcp ? 'requested' : 'unknown';
if (category === 'unknown') {
ctx.recordToolRequest?.({ toolName, reason, category: 'unknown' });
return {
output:
`"${toolName}" というツールは存在しません(要求は記録しました)。利用可能なツールで進めてください。` +
` 何が使えるかは ReadToolDoc などで確認できます。`,
isError: false,
};
}
// available_not_allowed. If this run can reach a user, pause for inline
// approval (blocking permission-prompt). Otherwise record auto_denied and
// let the agent proceed without it (the user finds the request later).
if (ctx.toolApprovalInteractive) {
ctx.recordToolRequest?.({ toolName, reason, category: 'requested', status: 'pending' });
ctx.pendingToolApproval = { toolName };
return {
output:
`"${toolName}" の利用にはユーザーの承認が必要です。承認/拒否を待っています。` +
` 承認されればこのまま続行でき、拒否されればそのツール無しで進めることになります。`,
isError: false,
};
}
ctx.recordToolRequest?.({ toolName, reason, category: 'requested', status: 'auto_denied' });
return {
output:
`"${toolName}" はこの movement では許可されていないため使えません(要求を記録しました)。` +
` このツール無しで進めるか、達成できない場合は complete({status:"needs_user_input", missing_info:"..."}) でユーザーに依頼してください。` +
` ピースの allowed_tools / shared_tools に追加すると次回から使えます。`,
isError: false,
};
}