diff --git a/app/Http/Controllers/Api/DaemonController.php b/app/Http/Controllers/Api/DaemonController.php index c5e7aa7..564f965 100644 --- a/app/Http/Controllers/Api/DaemonController.php +++ b/app/Http/Controllers/Api/DaemonController.php @@ -15,6 +15,7 @@ use App\Models\Approval; use App\Models\Server; use App\Models\Task; +use App\Models\TaskWorkProduct; use App\Models\UsageEvent; use App\Services\AuditService; use App\Services\TaskCheckoutService; @@ -170,6 +171,21 @@ public function reportResult(ReportResultRequest $request, string $token, Task $ ]); } + // Create work product records + if (! empty($validated['work_products'])) { + foreach ($validated['work_products'] as $wp) { + TaskWorkProduct::query()->create([ + 'task_id' => $task->id, + 'agent_id' => $task->agent_id, + 'type' => $wp['type'] ?? 'file', + 'title' => $wp['title'], + 'file_path' => $wp['file_path'] ?? null, + 'url' => $wp['url'] ?? null, + 'summary' => $wp['summary'] ?? null, + ]); + } + } + // Process delegations — create sub-tasks for named direct reports if (! empty($validated['delegations']) && $task->agent?->delegation_enabled) { foreach ($validated['delegations'] as $delegation) { diff --git a/app/Http/Controllers/GovernanceTaskController.php b/app/Http/Controllers/GovernanceTaskController.php index 571f120..a09fc2e 100644 --- a/app/Http/Controllers/GovernanceTaskController.php +++ b/app/Http/Controllers/GovernanceTaskController.php @@ -96,6 +96,7 @@ public function show(Request $request, Task $task): Response 'parentTask', 'subTasks.agent', 'usageEvents', + 'workProducts', ]); $auditEntries = $task->team->auditLogs() diff --git a/app/Http/Controllers/TaskWorkProductController.php b/app/Http/Controllers/TaskWorkProductController.php new file mode 100644 index 0000000..081adf6 --- /dev/null +++ b/app/Http/Controllers/TaskWorkProductController.php @@ -0,0 +1,84 @@ +team_id === $request->user()->current_team_id, 403); + abort_unless($taskWorkProduct->task_id === $task->id, 404); + abort_unless($taskWorkProduct->file_path, 404, 'Work product has no file path.'); + + $agent = $task->agent; + abort_unless($agent, 404, 'Task has no assigned agent.'); + + $server = $agent->server; + abort_unless($server, 404, 'Agent has no server.'); + + $basePath = $agent->harness_type === HarnessType::Hermes + ? "/root/.hermes-{$agent->harness_agent_id}/workspace/" + : "/root/.openclaw/agents/{$agent->harness_agent_id}/"; + + $filePath = $this->sanitizePath($taskWorkProduct->file_path); + + if (! $filePath) { + return response()->json(['message' => 'Invalid file path.'], 422); + } + + $fullPath = $basePath.$filePath; + + $this->sshService->connect($server); + + try { + $content = $this->sshService->readFile($fullPath); + } catch (RuntimeException) { + $this->sshService->disconnect(); + + return response()->json(['message' => 'File not found on server.'], 404); + } finally { + $this->sshService->disconnect(); + } + + $filename = basename($filePath); + + return response()->streamDownload(function () use ($content) { + echo $content; + }, $filename); + } + + /** + * Sanitize a file path to prevent directory traversal. + */ + private function sanitizePath(string $path): string + { + $path = str_replace("\0", '', $path); + $path = str_replace('\\', '/', $path); + $path = ltrim($path, '/'); + + $segments = explode('/', $path); + $clean = []; + foreach ($segments as $segment) { + if ($segment === '' || $segment === '.' || $segment === '..') { + continue; + } + $clean[] = $segment; + } + + return implode('/', $clean); + } +} diff --git a/app/Http/Requests/Governance/ReportResultRequest.php b/app/Http/Requests/Governance/ReportResultRequest.php index 1d0a2fa..3a2e92e 100644 --- a/app/Http/Requests/Governance/ReportResultRequest.php +++ b/app/Http/Requests/Governance/ReportResultRequest.php @@ -33,6 +33,12 @@ public function rules(): array 'approval_requests.*.type' => ['required_with:approval_requests', 'string'], 'approval_requests.*.title' => ['required_with:approval_requests', 'string', 'max:255'], 'approval_requests.*.payload' => ['nullable', 'array'], + 'work_products' => ['nullable', 'array'], + 'work_products.*.title' => ['required_with:work_products', 'string', 'max:255'], + 'work_products.*.file_path' => ['nullable', 'string', 'max:1000'], + 'work_products.*.url' => ['nullable', 'string', 'max:2000'], + 'work_products.*.type' => ['nullable', 'string', 'max:50'], + 'work_products.*.summary' => ['nullable', 'string', 'max:5000'], ]; } } diff --git a/app/Models/Task.php b/app/Models/Task.php index 1525603..c9f2600 100644 --- a/app/Models/Task.php +++ b/app/Models/Task.php @@ -129,6 +129,14 @@ public function delegatedByAgent(): BelongsTo return $this->belongsTo(Agent::class, 'delegated_by'); } + /** + * @return HasMany + */ + public function workProducts(): HasMany + { + return $this->hasMany(TaskWorkProduct::class); + } + /** * @return HasMany */ diff --git a/app/Models/TaskWorkProduct.php b/app/Models/TaskWorkProduct.php new file mode 100644 index 0000000..b7d7d9d --- /dev/null +++ b/app/Models/TaskWorkProduct.php @@ -0,0 +1,42 @@ + + */ + protected $fillable = [ + 'task_id', + 'agent_id', + 'type', + 'title', + 'file_path', + 'url', + 'summary', + ]; + + /** + * @return BelongsTo + */ + public function task(): BelongsTo + { + return $this->belongsTo(Task::class); + } + + /** + * @return BelongsTo + */ + public function agent(): BelongsTo + { + return $this->belongsTo(Agent::class); + } +} diff --git a/database/factories/TaskWorkProductFactory.php b/database/factories/TaskWorkProductFactory.php new file mode 100644 index 0000000..33e4262 --- /dev/null +++ b/database/factories/TaskWorkProductFactory.php @@ -0,0 +1,29 @@ + + */ +class TaskWorkProductFactory extends Factory +{ + /** + * @return array + */ + public function definition(): array + { + return [ + 'task_id' => Task::factory(), + 'agent_id' => Agent::factory(), + 'type' => 'file', + 'title' => fake()->sentence(3), + 'file_path' => '/workspace/output/'.fake()->slug().'.md', + 'summary' => fake()->paragraph(), + ]; + } +} diff --git a/database/migrations/2026_04_08_220001_create_task_work_products_table.php b/database/migrations/2026_04_08_220001_create_task_work_products_table.php new file mode 100644 index 0000000..1493fe8 --- /dev/null +++ b/database/migrations/2026_04_08_220001_create_task_work_products_table.php @@ -0,0 +1,30 @@ +ulid('id')->primary(); + $table->foreignUlid('task_id')->constrained('tasks')->cascadeOnDelete(); + $table->foreignUlid('agent_id')->nullable()->constrained('agents')->nullOnDelete(); + $table->string('type')->default('file'); + $table->string('title'); + $table->text('file_path')->nullable(); + $table->text('url')->nullable(); + $table->text('summary')->nullable(); + $table->timestamps(); + + $table->index('task_id'); + }); + } + + public function down(): void + { + Schema::dropIfExists('task_work_products'); + } +}; diff --git a/packages/provisiond/bundle/provisiond.mjs b/packages/provisiond/bundle/provisiond.mjs index 480287f..27662ce 100755 --- a/packages/provisiond/bundle/provisiond.mjs +++ b/packages/provisiond/bundle/provisiond.mjs @@ -206,6 +206,7 @@ function buildPrompt(task) { lines.push(""); lines.push("## Instructions"); lines.push("Complete this task. You have access to your browser, terminal, and workspace."); + lines.push("Save files others need to ./shared/. Keep work-in-progress in your private workspace."); lines.push(""); lines.push("When done, provide a summary of what you accomplished."); if (directReports.length > 0) { @@ -216,17 +217,22 @@ function buildPrompt(task) { lines.push(""); lines.push("To request approval for a high-impact action:"); lines.push("APPROVAL_REQUEST: {type} | {title} | {description}"); + lines.push(""); + lines.push("To declare a file or deliverable you produced:"); + lines.push("WORK_PRODUCT: {title} | {file_path} | {summary}"); return lines.join("\n"); } // src/response-parser.ts var DELEGATE_PREFIX = "DELEGATE:"; var APPROVAL_PREFIX = "APPROVAL_REQUEST:"; +var WORK_PRODUCT_PREFIX = "WORK_PRODUCT:"; function parseResponse(text) { const lines = text.split("\n"); const summaryLines = []; const delegations = []; const approvalRequests = []; + const workProducts = []; for (const line of lines) { const trimmed = line.trim(); if (trimmed.startsWith(DELEGATE_PREFIX)) { @@ -249,10 +255,20 @@ function parseResponse(text) { } continue; } + if (trimmed.startsWith(WORK_PRODUCT_PREFIX)) { + const workProduct = parseWorkProduct(trimmed.slice(WORK_PRODUCT_PREFIX.length).trim()); + if (workProduct) { + workProducts.push(workProduct); + } else { + logger.warn("Malformed WORK_PRODUCT line, including in summary", { line: trimmed }); + summaryLines.push(line); + } + continue; + } summaryLines.push(line); } const resultSummary = summaryLines.join("\n").trim(); - return { resultSummary, delegations, approvalRequests }; + return { resultSummary, delegations, approvalRequests, workProducts }; } function parseDelegation(raw) { const parts = raw.split("|").map((s) => s.trim()); @@ -276,6 +292,17 @@ function parseApproval(raw) { description: parts.slice(2).join(" | ") }; } +function parseWorkProduct(raw) { + const parts = raw.split("|").map((s) => s.trim()); + if (parts.length < 1 || !parts[0]) { + return null; + } + return { + title: parts[0], + filePath: parts[1] || void 0, + summary: parts.length > 2 ? parts.slice(2).join(" | ") : void 0 + }; +} // src/executor.ts var OPENCLAW_DEFAULT_PORT = 18789; @@ -323,6 +350,12 @@ async function executeTask(task, config, api) { type: a.type, title: a.title, description: a.description + })), + work_products: parsed.workProducts.map((wp) => ({ + title: wp.title, + file_path: wp.filePath, + type: "file", + summary: wp.summary })) }; await api.reportResult(task.id, result); diff --git a/packages/provisiond/dist/executor.d.ts.map b/packages/provisiond/dist/executor.d.ts.map index 6fcbd63..740527b 100644 --- a/packages/provisiond/dist/executor.d.ts.map +++ b/packages/provisiond/dist/executor.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../src/executor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAE7D,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAc,MAAM,YAAY,CAAC;AAIpE,wBAAsB,WAAW,CAC/B,IAAI,EAAE,aAAa,EACnB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,kBAAkB,GACtB,OAAO,CAAC,IAAI,CAAC,CAiGf"} \ No newline at end of file +{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../src/executor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAE7D,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAc,MAAM,YAAY,CAAC;AAIpE,wBAAsB,WAAW,CAC/B,IAAI,EAAE,aAAa,EACnB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,kBAAkB,GACtB,OAAO,CAAC,IAAI,CAAC,CAuGf"} \ No newline at end of file diff --git a/packages/provisiond/dist/executor.js b/packages/provisiond/dist/executor.js index 452bdc5..01a6a97 100644 --- a/packages/provisiond/dist/executor.js +++ b/packages/provisiond/dist/executor.js @@ -71,6 +71,12 @@ export async function executeTask(task, config, api) { title: a.title, description: a.description, })), + work_products: parsed.workProducts.map((wp) => ({ + title: wp.title, + file_path: wp.filePath, + type: 'file', + summary: wp.summary, + })), }; await api.reportResult(task.id, result); // Step 8: Report usage diff --git a/packages/provisiond/dist/executor.js.map b/packages/provisiond/dist/executor.js.map index 32c2581..a641dae 100644 --- a/packages/provisiond/dist/executor.js.map +++ b/packages/provisiond/dist/executor.js.map @@ -1 +1 @@ -{"version":3,"file":"executor.js","sourceRoot":"","sources":["../src/executor.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"executor.js","sourceRoot":"","sources":["../src/executor.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/provisiond/dist/prompt-builder.d.ts.map b/packages/provisiond/dist/prompt-builder.d.ts.map index 0f2de78..044ee13 100644 --- a/packages/provisiond/dist/prompt-builder.d.ts.map +++ b/packages/provisiond/dist/prompt-builder.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"prompt-builder.d.ts","sourceRoot":"","sources":["../src/prompt-builder.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,wBAAgB,WAAW,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAkEvD"} \ No newline at end of file +{"version":3,"file":"prompt-builder.d.ts","sourceRoot":"","sources":["../src/prompt-builder.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,wBAAgB,WAAW,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAuEvD"} \ No newline at end of file diff --git a/packages/provisiond/dist/prompt-builder.js b/packages/provisiond/dist/prompt-builder.js index 51bad5a..a03e1ff 100644 --- a/packages/provisiond/dist/prompt-builder.js +++ b/packages/provisiond/dist/prompt-builder.js @@ -48,6 +48,7 @@ export function buildPrompt(task) { lines.push(''); lines.push('## Instructions'); lines.push('Complete this task. You have access to your browser, terminal, and workspace.'); + lines.push('Save files others need to ./shared/. Keep work-in-progress in your private workspace.'); lines.push(''); lines.push('When done, provide a summary of what you accomplished.'); if (directReports.length > 0) { @@ -58,6 +59,9 @@ export function buildPrompt(task) { lines.push(''); lines.push('To request approval for a high-impact action:'); lines.push('APPROVAL_REQUEST: {type} | {title} | {description}'); + lines.push(''); + lines.push('To declare a file or deliverable you produced:'); + lines.push('WORK_PRODUCT: {title} | {file_path} | {summary}'); return lines.join('\n'); } //# sourceMappingURL=prompt-builder.js.map \ No newline at end of file diff --git a/packages/provisiond/dist/prompt-builder.js.map b/packages/provisiond/dist/prompt-builder.js.map index ada05f7..3ff70e4 100644 --- a/packages/provisiond/dist/prompt-builder.js.map +++ b/packages/provisiond/dist/prompt-builder.js.map @@ -1 +1 @@ -{"version":3,"file":"prompt-builder.js","sourceRoot":"","sources":["../src/prompt-builder.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"prompt-builder.js","sourceRoot":"","sources":["../src/prompt-builder.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/provisiond/dist/response-parser.d.ts b/packages/provisiond/dist/response-parser.d.ts index f4b5272..e47174b 100644 --- a/packages/provisiond/dist/response-parser.d.ts +++ b/packages/provisiond/dist/response-parser.d.ts @@ -1,12 +1,14 @@ /** * Parses the agent's response text to extract delegations, approval requests, - * and the main result summary. + * work products, and the main result summary. * * Parsing rules: * - Lines starting with "DELEGATE:" are extracted as delegations. * Format: DELEGATE: {agent_name} | {title} | {description} * - Lines starting with "APPROVAL_REQUEST:" are extracted as approval requests. * Format: APPROVAL_REQUEST: {type} | {title} | {description} + * - Lines starting with "WORK_PRODUCT:" are extracted as work products. + * Format: WORK_PRODUCT: {title} | {file_path} | {summary} * - Everything else becomes the result summary. */ import type { ParsedResponse } from './types.js'; diff --git a/packages/provisiond/dist/response-parser.d.ts.map b/packages/provisiond/dist/response-parser.d.ts.map index fa32bf5..b56484f 100644 --- a/packages/provisiond/dist/response-parser.d.ts.map +++ b/packages/provisiond/dist/response-parser.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"response-parser.d.ts","sourceRoot":"","sources":["../src/response-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAKjD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAqC1D"} \ No newline at end of file +{"version":3,"file":"response-parser.d.ts","sourceRoot":"","sources":["../src/response-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAMjD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAiD1D"} \ No newline at end of file diff --git a/packages/provisiond/dist/response-parser.js b/packages/provisiond/dist/response-parser.js index b462152..977f558 100644 --- a/packages/provisiond/dist/response-parser.js +++ b/packages/provisiond/dist/response-parser.js @@ -1,22 +1,26 @@ /** * Parses the agent's response text to extract delegations, approval requests, - * and the main result summary. + * work products, and the main result summary. * * Parsing rules: * - Lines starting with "DELEGATE:" are extracted as delegations. * Format: DELEGATE: {agent_name} | {title} | {description} * - Lines starting with "APPROVAL_REQUEST:" are extracted as approval requests. * Format: APPROVAL_REQUEST: {type} | {title} | {description} + * - Lines starting with "WORK_PRODUCT:" are extracted as work products. + * Format: WORK_PRODUCT: {title} | {file_path} | {summary} * - Everything else becomes the result summary. */ import { logger } from './logger.js'; const DELEGATE_PREFIX = 'DELEGATE:'; const APPROVAL_PREFIX = 'APPROVAL_REQUEST:'; +const WORK_PRODUCT_PREFIX = 'WORK_PRODUCT:'; export function parseResponse(text) { const lines = text.split('\n'); const summaryLines = []; const delegations = []; const approvalRequests = []; + const workProducts = []; for (const line of lines) { const trimmed = line.trim(); if (trimmed.startsWith(DELEGATE_PREFIX)) { @@ -41,10 +45,21 @@ export function parseResponse(text) { } continue; } + if (trimmed.startsWith(WORK_PRODUCT_PREFIX)) { + const workProduct = parseWorkProduct(trimmed.slice(WORK_PRODUCT_PREFIX.length).trim()); + if (workProduct) { + workProducts.push(workProduct); + } + else { + logger.warn('Malformed WORK_PRODUCT line, including in summary', { line: trimmed }); + summaryLines.push(line); + } + continue; + } summaryLines.push(line); } const resultSummary = summaryLines.join('\n').trim(); - return { resultSummary, delegations, approvalRequests }; + return { resultSummary, delegations, approvalRequests, workProducts }; } function parseDelegation(raw) { const parts = raw.split('|').map((s) => s.trim()); @@ -68,4 +83,15 @@ function parseApproval(raw) { description: parts.slice(2).join(' | '), }; } +function parseWorkProduct(raw) { + const parts = raw.split('|').map((s) => s.trim()); + if (parts.length < 1 || !parts[0]) { + return null; + } + return { + title: parts[0], + filePath: parts[1] || undefined, + summary: parts.length > 2 ? parts.slice(2).join(' | ') : undefined, + }; +} //# sourceMappingURL=response-parser.js.map \ No newline at end of file diff --git a/packages/provisiond/dist/response-parser.js.map b/packages/provisiond/dist/response-parser.js.map index 07a4359..51a0907 100644 --- a/packages/provisiond/dist/response-parser.js.map +++ b/packages/provisiond/dist/response-parser.js.map @@ -1 +1 @@ -{"version":3,"file":"response-parser.js","sourceRoot":"","sources":["../src/response-parser.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"response-parser.js","sourceRoot":"","sources":["../src/response-parser.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/provisiond/dist/types.d.ts b/packages/provisiond/dist/types.d.ts index b1c202e..55d8fa5 100644 --- a/packages/provisiond/dist/types.d.ts +++ b/packages/provisiond/dist/types.d.ts @@ -58,6 +58,13 @@ export interface TaskResult { title: string; description: string; }>; + work_products: Array<{ + title: string; + file_path?: string; + url?: string; + type?: string; + summary?: string; + }>; } export interface GatewayResponse { outputText: string; @@ -77,6 +84,11 @@ export interface ParsedResponse { title: string; description: string; }>; + workProducts: Array<{ + title: string; + filePath?: string; + summary?: string; + }>; } export interface ResolvedApproval { id: string; diff --git a/packages/provisiond/dist/types.d.ts.map b/packages/provisiond/dist/types.d.ts.map index 81f095d..2d3422b 100644 --- a/packages/provisiond/dist/types.d.ts.map +++ b/packages/provisiond/dist/types.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/provisiond/src/executor.ts b/packages/provisiond/src/executor.ts index 9fa87e4..a81d8fd 100644 --- a/packages/provisiond/src/executor.ts +++ b/packages/provisiond/src/executor.ts @@ -88,6 +88,12 @@ export async function executeTask( title: a.title, description: a.description, })), + work_products: parsed.workProducts.map((wp) => ({ + title: wp.title, + file_path: wp.filePath, + type: 'file', + summary: wp.summary, + })), }; await api.reportResult(task.id, result); diff --git a/packages/provisiond/src/prompt-builder.ts b/packages/provisiond/src/prompt-builder.ts index c8d395c..5b8043a 100644 --- a/packages/provisiond/src/prompt-builder.ts +++ b/packages/provisiond/src/prompt-builder.ts @@ -58,6 +58,7 @@ export function buildPrompt(task: WorkQueueTask): string { lines.push(''); lines.push('## Instructions'); lines.push('Complete this task. You have access to your browser, terminal, and workspace.'); + lines.push('Save files others need to ./shared/. Keep work-in-progress in your private workspace.'); lines.push(''); lines.push('When done, provide a summary of what you accomplished.'); @@ -71,5 +72,9 @@ export function buildPrompt(task: WorkQueueTask): string { lines.push('To request approval for a high-impact action:'); lines.push('APPROVAL_REQUEST: {type} | {title} | {description}'); + lines.push(''); + lines.push('To declare a file or deliverable you produced:'); + lines.push('WORK_PRODUCT: {title} | {file_path} | {summary}'); + return lines.join('\n'); } diff --git a/packages/provisiond/src/response-parser.ts b/packages/provisiond/src/response-parser.ts index dfa52ff..4728199 100644 --- a/packages/provisiond/src/response-parser.ts +++ b/packages/provisiond/src/response-parser.ts @@ -1,12 +1,14 @@ /** * Parses the agent's response text to extract delegations, approval requests, - * and the main result summary. + * work products, and the main result summary. * * Parsing rules: * - Lines starting with "DELEGATE:" are extracted as delegations. * Format: DELEGATE: {agent_name} | {title} | {description} * - Lines starting with "APPROVAL_REQUEST:" are extracted as approval requests. * Format: APPROVAL_REQUEST: {type} | {title} | {description} + * - Lines starting with "WORK_PRODUCT:" are extracted as work products. + * Format: WORK_PRODUCT: {title} | {file_path} | {summary} * - Everything else becomes the result summary. */ @@ -15,12 +17,14 @@ import type { ParsedResponse } from './types.js'; const DELEGATE_PREFIX = 'DELEGATE:'; const APPROVAL_PREFIX = 'APPROVAL_REQUEST:'; +const WORK_PRODUCT_PREFIX = 'WORK_PRODUCT:'; export function parseResponse(text: string): ParsedResponse { const lines = text.split('\n'); const summaryLines: string[] = []; const delegations: ParsedResponse['delegations'] = []; const approvalRequests: ParsedResponse['approvalRequests'] = []; + const workProducts: ParsedResponse['workProducts'] = []; for (const line of lines) { const trimmed = line.trim(); @@ -47,12 +51,23 @@ export function parseResponse(text: string): ParsedResponse { continue; } + if (trimmed.startsWith(WORK_PRODUCT_PREFIX)) { + const workProduct = parseWorkProduct(trimmed.slice(WORK_PRODUCT_PREFIX.length).trim()); + if (workProduct) { + workProducts.push(workProduct); + } else { + logger.warn('Malformed WORK_PRODUCT line, including in summary', { line: trimmed }); + summaryLines.push(line); + } + continue; + } + summaryLines.push(line); } const resultSummary = summaryLines.join('\n').trim(); - return { resultSummary, delegations, approvalRequests }; + return { resultSummary, delegations, approvalRequests, workProducts }; } function parseDelegation( @@ -82,3 +97,17 @@ function parseApproval( description: parts.slice(2).join(' | '), }; } + +function parseWorkProduct( + raw: string, +): ParsedResponse['workProducts'][number] | null { + const parts = raw.split('|').map((s) => s.trim()); + if (parts.length < 1 || !parts[0]) { + return null; + } + return { + title: parts[0], + filePath: parts[1] || undefined, + summary: parts.length > 2 ? parts.slice(2).join(' | ') : undefined, + }; +} diff --git a/packages/provisiond/src/types.ts b/packages/provisiond/src/types.ts index abdbbf3..8f3655e 100644 --- a/packages/provisiond/src/types.ts +++ b/packages/provisiond/src/types.ts @@ -61,6 +61,13 @@ export interface TaskResult { title: string; description: string; }>; + work_products: Array<{ + title: string; + file_path?: string; + url?: string; + type?: string; + summary?: string; + }>; } export interface GatewayResponse { @@ -82,6 +89,11 @@ export interface ParsedResponse { title: string; description: string; }>; + workProducts: Array<{ + title: string; + filePath?: string; + summary?: string; + }>; } export interface ResolvedApproval { diff --git a/resources/js/components/task-work-products.tsx b/resources/js/components/task-work-products.tsx new file mode 100644 index 0000000..cda0795 --- /dev/null +++ b/resources/js/components/task-work-products.tsx @@ -0,0 +1,95 @@ +import { Download, ExternalLink, FileText, Globe, Package } from 'lucide-react'; +import { Badge } from '@/components/ui/badge'; +import { Button } from '@/components/ui/button'; +import type { TaskWorkProduct } from '@/types'; + +const TYPE_ICONS: Record = { + file: , + url: , +}; + +export default function TaskWorkProducts({ + workProducts, + taskId, +}: { + workProducts: TaskWorkProduct[]; + taskId: string; +}) { + if (workProducts.length === 0) { + return null; + } + + return ( +
+

+ + Work Products ({workProducts.length}) +

+
+ {workProducts.map((wp) => ( +
+
+ {TYPE_ICONS[wp.type] ?? ( + + )} +
+
+
+ + {wp.title} + + + {wp.type} + +
+ {wp.summary && ( +

+ {wp.summary} +

+ )} + {wp.file_path && ( +

+ {wp.file_path} +

+ )} +
+
+ {wp.file_path && ( + + )} + {wp.url && ( + + )} +
+
+ ))} +
+
+ ); +} diff --git a/resources/js/pages/company/tasks/show.tsx b/resources/js/pages/company/tasks/show.tsx index d85bea7..a666fad 100644 --- a/resources/js/pages/company/tasks/show.tsx +++ b/resources/js/pages/company/tasks/show.tsx @@ -1,6 +1,7 @@ import { Head, Link } from '@inertiajs/react'; import { ChevronRight, Clock, Cpu, FileText, ListTree } from 'lucide-react'; import Markdown from 'react-markdown'; +import TaskWorkProducts from '@/components/task-work-products'; import { Badge } from '@/components/ui/badge'; import AppLayout from '@/layouts/app-layout'; import type { @@ -196,6 +197,14 @@ export default function TaskShow({ )} + {/* Work products */} + {task.work_products && task.work_products.length > 0 && ( + + )} + {/* Sub-tasks */} {subTasks.length > 0 && (
diff --git a/resources/js/types/auth.ts b/resources/js/types/auth.ts index a06cd9f..06620c4 100644 --- a/resources/js/types/auth.ts +++ b/resources/js/types/auth.ts @@ -455,6 +455,19 @@ export type Goal = { parent?: Goal; }; +export type TaskWorkProduct = { + id: string; + task_id: string; + agent_id: string | null; + type: string; + title: string; + file_path: string | null; + url: string | null; + summary: string | null; + created_at: string; + updated_at: string; +}; + export type GovernanceTask = { id: string; identifier: string; @@ -486,6 +499,7 @@ export type GovernanceTask = { goal?: Goal; parent_task?: GovernanceTask; sub_tasks?: GovernanceTask[]; + work_products?: TaskWorkProduct[]; }; export type Approval = { diff --git a/routes/web.php b/routes/web.php index 15aceb4..45c9328 100644 --- a/routes/web.php +++ b/routes/web.php @@ -18,6 +18,7 @@ use App\Http\Controllers\GovernanceTaskController; use App\Http\Controllers\OrgChartController; use App\Http\Controllers\ProfileSetupController; +use App\Http\Controllers\SharedWorkspaceController; use App\Http\Controllers\SlackConnectionController; use App\Http\Controllers\TeamPackController; use App\Http\Controllers\TelegramConnectionController; @@ -192,6 +193,13 @@ Route::get('company/agents/{agent}/usage', [UsageController::class, 'forAgent'])->name('company.usage.forAgent'); Route::get('company/audit', [AuditLogController::class, 'index'])->name('company.audit.index'); + + // Shared workspace + Route::get('company/workspace', [SharedWorkspaceController::class, 'index'])->name('company.workspace.index'); + Route::post('company/workspace/upload', [SharedWorkspaceController::class, 'upload'])->name('company.workspace.upload'); + Route::post('company/workspace/folder', [SharedWorkspaceController::class, 'createFolder'])->name('company.workspace.folder'); + Route::delete('company/workspace', [SharedWorkspaceController::class, 'destroy'])->name('company.workspace.destroy'); + Route::get('company/workspace/download', [SharedWorkspaceController::class, 'download'])->name('company.workspace.download'); }); require __DIR__.'/settings.php'; diff --git a/tests/Feature/Governance/TaskWorkProductTest.php b/tests/Feature/Governance/TaskWorkProductTest.php new file mode 100644 index 0000000..1e0d5d5 --- /dev/null +++ b/tests/Feature/Governance/TaskWorkProductTest.php @@ -0,0 +1,159 @@ +withPersonalTeam()->create(); + $team = $user->currentTeam; + + $server = Server::factory()->running()->create([ + 'team_id' => $team->id, + 'daemon_token' => 'wp-test-token-123', + ]); + + $agent = Agent::factory()->create([ + 'team_id' => $team->id, + 'server_id' => $server->id, + 'agent_mode' => AgentMode::Workforce, + ]); + + $task = Task::factory()->inProgress()->create([ + 'team_id' => $team->id, + 'agent_id' => $agent->id, + 'checked_out_by_run' => 'run-wp-1', + ]); + + return [$user, $team, $server, $agent, $task]; +} + +it('creates work products when daemon reports result with work_products', function () { + [, , , , $task] = workProductSetup(); + + $response = $this->postJson("/api/daemon/wp-test-token-123/tasks/{$task->id}/result", [ + 'daemon_run_id' => 'run-wp-1', + 'status' => 'done', + 'result_summary' => 'Completed with deliverables.', + 'work_products' => [ + [ + 'title' => 'Market Analysis Report', + 'file_path' => '/workspace/output/market-analysis.md', + 'summary' => 'Comprehensive market analysis for Q2.', + ], + [ + 'title' => 'Competitor Spreadsheet', + 'file_path' => '/workspace/output/competitors.csv', + 'summary' => 'Competitor pricing comparison.', + ], + ], + ]); + + $response->assertOk(); + + expect(TaskWorkProduct::where('task_id', $task->id)->count())->toBe(2); +}); + +it('stores work products with correct attributes', function () { + [, , , $agent, $task] = workProductSetup(); + + $this->postJson("/api/daemon/wp-test-token-123/tasks/{$task->id}/result", [ + 'daemon_run_id' => 'run-wp-1', + 'status' => 'done', + 'work_products' => [ + [ + 'type' => 'report', + 'title' => 'Final Deliverable', + 'file_path' => '/workspace/output/final.pdf', + 'summary' => 'The final report.', + ], + ], + ]); + + $wp = TaskWorkProduct::where('task_id', $task->id)->first(); + + expect($wp)->not->toBeNull() + ->and($wp->task_id)->toBe($task->id) + ->and($wp->agent_id)->toBe($agent->id) + ->and($wp->type)->toBe('report') + ->and($wp->title)->toBe('Final Deliverable') + ->and($wp->file_path)->toBe('/workspace/output/final.pdf') + ->and($wp->summary)->toBe('The final report.'); +}); + +it('loads work products in task show page', function () { + $this->withoutVite(); + + [$user, , , $agent, $task] = workProductSetup(); + + TaskWorkProduct::factory()->count(2)->create([ + 'task_id' => $task->id, + 'agent_id' => $agent->id, + ]); + + $response = $this->actingAs($user) + ->get(route('company.tasks.show', $task)); + + $response->assertOk(); + $response->assertInertia(fn ($page) => $page + ->component('company/tasks/show') + ->has('task.work_products', 2) + ); +}); + +it('handles result without work products gracefully', function () { + [, , , , $task] = workProductSetup(); + + $response = $this->postJson("/api/daemon/wp-test-token-123/tasks/{$task->id}/result", [ + 'daemon_run_id' => 'run-wp-1', + 'status' => 'done', + 'result_summary' => 'Done without deliverables.', + ]); + + $response->assertOk(); + + expect(TaskWorkProduct::where('task_id', $task->id)->count())->toBe(0); +}); + +it('validates work product fields', function () { + [, , , , $task] = workProductSetup(); + + $response = $this->postJson("/api/daemon/wp-test-token-123/tasks/{$task->id}/result", [ + 'daemon_run_id' => 'run-wp-1', + 'status' => 'done', + 'work_products' => [ + [ + 'title' => str_repeat('x', 256), + 'file_path' => '/workspace/output/too-long-title.md', + 'summary' => 'Title exceeds max length.', + ], + ], + ]); + + $response->assertUnprocessable(); + $response->assertJsonValidationErrors(['work_products.0.title']); +}); + +it('associates work products with the task agent', function () { + [, , , $agent, $task] = workProductSetup(); + + $this->postJson("/api/daemon/wp-test-token-123/tasks/{$task->id}/result", [ + 'daemon_run_id' => 'run-wp-1', + 'status' => 'done', + 'work_products' => [ + [ + 'title' => 'Agent Output', + 'file_path' => '/workspace/output/agent-output.md', + ], + ], + ]); + + $wp = TaskWorkProduct::where('task_id', $task->id)->first(); + + expect($wp->agent_id)->toBe($agent->id) + ->and($wp->agent_id)->toBe($task->agent_id); +});