feat(agents): 完善恢复费用与云资源交互
This commit is contained in:
@@ -9,8 +9,31 @@ const request = ['request_id', 'thread_id', 'run_id', 'status', 'version'];
|
||||
const schedule = ['name', 'prompt', 'cron_expression', 'timezone', 'enabled'];
|
||||
const job = ['id', 'agent_slug', ...schedule, 'next_run_at', 'runs'];
|
||||
const entry = ['slug', 'name', 'purpose', 'published_version', 'is_creator', 'payer'];
|
||||
const budget = ['agent_slug', 'unit', 'timezone', 'request_limit_points', 'daily_limit_points', 'daily_committed_points', 'resets_at'];
|
||||
const draft = ['slug', 'name', 'purpose', 'system_prompt', 'draft_revision', 'updated_at', 'configuration', 'published_version', 'enabled', 'archived'];
|
||||
const mcpInput = ['name', 'description', 'transport', 'url', 'headers'];
|
||||
const mcpOutput = ['slug', 'name', 'description', 'transport', 'url', 'enabled', 'has_credentials'];
|
||||
const child = ['name', 'purpose', 'system_prompt'];
|
||||
/** Only these product operations can cross the Main boundary; no arbitrary upstream URL or credentials. */
|
||||
const operations: Record<keyof CloudAgentOperations, OperationSpec> = {
|
||||
applicationCalls: { method: 'GET', path: '/applications/:application_id/calls', query: { offset: 'offset' }, output: ['items', 'next_offset'] },
|
||||
resources: { method: 'GET', path: '/resources', output: ['mcps', 'skills', 'subagents'] },
|
||||
createMcp: { method: 'POST', path: '/resources/mcps', body: [...mcpInput, 'operation_id'], output: mcpOutput },
|
||||
updateMcp: { method: 'PUT', path: '/resources/mcps/:key', body: mcpInput, output: mcpOutput },
|
||||
enableMcp: { method: 'PUT', path: '/resources/mcps/:key/enabled', body: ['enabled'], output: mcpOutput },
|
||||
deleteMcp: { method: 'DELETE', path: '/resources/mcps/:key', output: ['deleted'] },
|
||||
createChild: { method: 'POST', path: '/resources/subagents', body: [...child, 'operation_id'], output: ['slug', ...child] },
|
||||
updateChild: { method: 'PUT', path: '/resources/subagents/:key', body: child, output: ['slug', ...child] },
|
||||
confirmSkill: { method: 'POST', path: '/resources/skills/drafts/:draft_id/confirm', output: ['items'] },
|
||||
deleteSkill: { method: 'DELETE', path: '/resources/skills/:key', output: ['deleted'] },
|
||||
deleteKnowledge: { method: 'DELETE', path: '/agents/:slug/knowledge/:kb_id', output: ['deleted'] },
|
||||
deleteKnowledgeFile: { method: 'DELETE', path: '/agents/:slug/knowledge/:kb_id/files/:file_id', output: ['deleted'] },
|
||||
importKnowledgeAttachment: { method: 'POST', path: '/agents/:slug/knowledge/:kb_id/import-attachment', body: ['operation_id', 'thread_id', 'attachment_id'], output: ['file_id', 'name', 'size', 'status', 'error', 'chunk_count'] },
|
||||
archiveAgent: { method: 'PUT', path: '/agents/:slug/archive', body: ['archived'], output: draft },
|
||||
archiveThread: { method: 'PUT', path: '/threads/:thread_id/archive', body: ['archived'], output: ['thread_id', 'archived'] },
|
||||
version: { method: 'GET', path: '/agents/:slug/versions/:version', output: ['version', 'created_at', 'name', 'purpose', 'system_prompt', 'configuration'] },
|
||||
restoreVersion: { method: 'POST', path: '/agents/:slug/versions/:version/restore', body: ['expected_revision'], output: draft },
|
||||
scheduleContext: { method: 'GET', path: '/agents/:slug/schedule-context', output: ['version', 'enabled', 'configuration', 'result_destination', 'payer'] },
|
||||
knowledge: { method: 'GET', path: '/agents/:slug/knowledge', output: ['databases', 'models'] },
|
||||
createKnowledge: { method: 'POST', path: '/agents/:slug/knowledge', body: ['operation_id', 'name', 'embedding_model'], output: ['kb_id', 'name', 'description', 'embedding_model'] },
|
||||
knowledgeFiles: { method: 'GET', path: '/agents/:slug/knowledge/:kb_id/files', query: { offset: 'offset' }, output: ['files', 'next_offset'] },
|
||||
@@ -28,10 +51,12 @@ const operations: Record<keyof CloudAgentOperations, OperationSpec> = {
|
||||
keys: { method: 'GET', path: '/applications/:application_id/keys', output: ['keys'] },
|
||||
createKey: { method: 'POST', path: '/applications/:application_id/keys', body: ['operation_id'], output: ['id', 'prefix', 'secret'] },
|
||||
revokeKey: { method: 'DELETE', path: '/applications/:application_id/keys/:key_id', output: ['revoked'] },
|
||||
costs: { method: 'GET', cloud: 'ws', path: '/costs', query: { slug: 'agent_slug' }, output: ['unit', 'items'] },
|
||||
threads: { method: 'GET', path: '/threads', query: { slug: 'slug', offset: 'offset' }, output: ['threads', 'next_offset'] },
|
||||
costs: { method: 'GET', cloud: 'ws', path: '/costs', query: { slug: 'agent_slug', offset: 'offset', started_at: 'started_at', ended_at: 'ended_at', source: 'source', application_id: 'application_id' }, output: ['unit', 'items', 'next_offset', 'summary'] },
|
||||
budget: { method: 'GET', cloud: 'ws', path: '/agents/:slug/budget', output: budget },
|
||||
saveBudget: { method: 'PUT', cloud: 'ws', path: '/agents/:slug/budget', body: ['request_limit_points', 'daily_limit_points'], output: budget },
|
||||
threads: { method: 'GET', path: '/threads', query: { slug: 'slug', offset: 'offset', archived: 'archived' }, output: ['threads', 'next_offset'] },
|
||||
createThread: { method: 'POST', path: '/agents/:slug/threads', body: ['thread_id', 'preview', 'expected_revision'], output: ['thread_id', 'client_thread_id'] },
|
||||
history: { method: 'GET', path: '/threads/:thread_id', query: { offset: 'offset' }, output: ['thread_id', 'messages', 'run', 'next_offset'] },
|
||||
history: { method: 'GET', path: '/threads/:thread_id', query: { offset: 'offset' }, output: ['thread_id', 'messages', 'run', 'queued_requests', 'schedule_proposals', 'next_offset'] },
|
||||
viewed: { method: 'POST', path: '/threads/:thread_id/viewed', body: ['run_id'], output: ['viewed'] },
|
||||
submit: { method: 'POST', path: '/agents/:slug/requests', body: prompt, output: request },
|
||||
preview: { method: 'POST', path: '/agents/:slug/preview', body: prompt, output: request },
|
||||
@@ -59,6 +84,7 @@ export function operationPlan(value: unknown) {
|
||||
|| !input || typeof input !== 'object' || Array.isArray(input)) throw new Error('invalid_operation');
|
||||
const spec = operations[operation as keyof CloudAgentOperations];
|
||||
const args = input as Record<string, unknown>;
|
||||
const routeKeys = [...spec.path.matchAll(/:([a-z_]+)/g)].map(match => match[1]);
|
||||
const path = spec.path.replace(/:([a-z_]+)/g, (_, key: string) => {
|
||||
const id = args[key];
|
||||
if (typeof id !== 'string' || !/^[a-zA-Z0-9_-]{1,128}$/.test(id)
|
||||
@@ -69,12 +95,15 @@ export function operationPlan(value: unknown) {
|
||||
for (const [key, name] of Object.entries(spec.query ?? {})) {
|
||||
const v = args[key];
|
||||
if (v === undefined) continue;
|
||||
if (key === 'offset' ? !Number.isSafeInteger(v) || Number(v) < 0 : typeof v !== 'string' || v.length > (key === 'path' ? 2048 : 100)) {
|
||||
if (key === 'archived' ? typeof v !== 'boolean' : key === 'offset' ? !Number.isSafeInteger(v) || Number(v) < 0 : typeof v !== 'string' || v.length > (key === 'path' ? 2048 : 100)) {
|
||||
throw new Error('invalid_query');
|
||||
}
|
||||
query.set(name, String(v));
|
||||
}
|
||||
return {
|
||||
operation,
|
||||
input: Object.fromEntries([...new Set([...routeKeys, ...(spec.body ?? []), ...Object.keys(spec.query ?? {})])]
|
||||
.filter(key => args[key] !== undefined).map(key => [key, args[key]])),
|
||||
...spec, path: (spec.cloud === 'ws' ? '/api/cloud-agents' : '/api/makelore') + path + (query.size ? '?' + query : ''),
|
||||
body: spec.body ? Object.fromEntries(spec.body.filter(key => args[key] !== undefined).map(key => [key, args[key]])) : undefined,
|
||||
project: (result: unknown) => {
|
||||
|
||||
Reference in New Issue
Block a user