@bluefly/openstandardagents 0.5.0 → 0.5.1
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/.version.json +3 -3
- package/CHANGELOG.md +43 -12
- package/README.md +31 -26
- package/bin/postinstall +0 -0
- package/dist/.version.json +3 -3
- package/dist/adapters/a2a/a2a-protocol.js +4 -2
- package/dist/adapters/a2a/a2a-tool.js +4 -2
- package/dist/adapters/a2a/mcp-integration.d.ts +2 -1
- package/dist/adapters/a2a/mcp-integration.js +6 -3
- package/dist/adapters/browser/browser-exporter.d.ts +26 -0
- package/dist/adapters/browser/browser-exporter.js +73 -0
- package/dist/adapters/browser/browser-runner.d.ts +23 -0
- package/dist/adapters/browser/browser-runner.js +46 -0
- package/dist/adapters/browser/index.d.ts +9 -0
- package/dist/adapters/browser/index.js +9 -0
- package/dist/adapters/docker/index.d.ts +2 -0
- package/dist/adapters/docker/index.js +2 -0
- package/dist/adapters/docker/openclaw-bridge.d.ts +57 -0
- package/dist/adapters/docker/openclaw-bridge.js +173 -0
- package/dist/adapters/drupal/index.d.ts +1 -0
- package/dist/adapters/drupal/index.js +2 -0
- package/dist/adapters/drupal/twig-renderer.d.ts +23 -0
- package/dist/adapters/drupal/twig-renderer.js +99 -0
- package/dist/adapters/gitlab/agent-generator.js +2 -1
- package/dist/api/index.js +2 -1
- package/dist/api/routes/mcp.router.js +3 -1
- package/dist/api/routes/wizard.router.js +3 -1
- package/dist/cli/commands/agent/discover-type.command.js +1 -1
- package/dist/cli/commands/agent-card.command.js +37 -10
- package/dist/cli/commands/agents-sync.command.d.ts +2 -2
- package/dist/cli/commands/agents-sync.command.js +27 -17
- package/dist/cli/commands/catalog/config.js +1 -1
- package/dist/cli/commands/catalog/validate.command.js +2 -2
- package/dist/cli/commands/config.command.js +2 -2
- package/dist/cli/commands/daemon.command.js +32 -8
- package/dist/cli/commands/discover.d.ts +1 -1
- package/dist/cli/commands/discover.js +16 -8
- package/dist/cli/commands/economics.command.d.ts +9 -0
- package/dist/cli/commands/economics.command.js +113 -0
- package/dist/cli/commands/export.command.js +6 -3
- package/dist/cli/commands/mcp.command.js +3 -1
- package/dist/cli/commands/memory.command.d.ts +18 -0
- package/dist/cli/commands/memory.command.js +168 -0
- package/dist/cli/commands/publish.command.js +7 -4
- package/dist/cli/commands/serve-builder-routes.js +1 -1
- package/dist/cli/commands/usie-skills.command.d.ts +24 -0
- package/dist/cli/commands/usie-skills.command.js +297 -0
- package/dist/cli/commands/validate.command.js +8 -1
- package/dist/cli/commands/verify.d.ts +3 -3
- package/dist/cli/commands/verify.js +12 -6
- package/dist/cli/commands/workspace.command.d.ts +1 -0
- package/dist/cli/commands/workspace.command.js +28 -4
- package/dist/cli/index.js +12 -0
- package/dist/cli/workspace-validate.d.ts +23 -0
- package/dist/cli/workspace-validate.js +117 -0
- package/dist/data/platform-matrix.js +1 -4
- package/dist/generated/types.d.ts +97 -97
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/mcp-server/index.js +658 -982
- package/dist/mesh/discovery-gkg.d.ts +26 -0
- package/dist/mesh/discovery-gkg.js +92 -0
- package/dist/messenger/Handler/AgentBatchHandler.js +3 -2
- package/dist/messenger/Handler/AgentExecutionHandler.js +6 -1
- package/dist/package.json +20 -4
- package/dist/sdks/shared/types.d.ts +1 -1
- package/dist/services/agent-card-generator.js +6 -2
- package/dist/services/daemon/audit-log.service.js +3 -1
- package/dist/services/daemon/execution.service.js +8 -4
- package/dist/services/daemon/fs-watcher.service.js +6 -7
- package/dist/services/daemon/pairing.service.js +2 -1
- package/dist/services/daemon/skill-aggregator.service.js +105 -21
- package/dist/services/daemon/sse-endpoints.js +1 -1
- package/dist/services/daemon/ws-server.js +10 -3
- package/dist/services/governance/cedar-provider.js +12 -8
- package/dist/services/governance/cedar-validator.service.js +1 -1
- package/dist/services/mcp/bridge.service.js +40 -9
- package/dist/services/openapi-extensions-validation.d.ts +20 -0
- package/dist/services/openapi-extensions-validation.js +193 -0
- package/dist/services/release-automation/merge-request.service.d.ts +4 -4
- package/dist/services/release-automation/release-buttons.js +3 -3
- package/dist/services/release-automation/schemas/release.schema.d.ts +3 -3
- package/dist/services/runtime/openai.adapter.d.ts +46 -13
- package/dist/services/runtime/openai.adapter.js +169 -131
- package/dist/services/skill-registry.service.d.ts +1 -1
- package/dist/services/skills-pipeline/skills-research.service.js +47 -7
- package/dist/services/trust/trust.service.js +6 -4
- package/dist/services/validation-zod.service.js +3 -22
- package/dist/services/validators/index.d.ts +1 -0
- package/dist/services/validators/index.js +1 -0
- package/dist/services/validators/registry.d.ts +21 -0
- package/dist/services/validators/registry.js +42 -0
- package/dist/skills/test-skill/package.json +1 -1
- package/dist/spec/extensions/cognition.schema.json +87 -0
- package/dist/spec/layer4-economics/duadp-examples.json +44 -0
- package/dist/spec/v0.4/agent.schema.json +14 -0
- package/dist/spec/v0.5/agent-builder-openapi.yaml +230 -0
- package/dist/spec/v0.5/agent.schema.json +32 -1
- package/dist/spec/v0.5/extensions/cognition/cognition.schema.json +78 -1
- package/dist/spec/v0.5/extensions/economics/context-pack.schema.json +91 -0
- package/dist/spec/v0.5/extensions/economics/execution-profile.schema.json +148 -0
- package/dist/spec/v0.5/extensions/economics/failure-semantics.schema.json +32 -0
- package/dist/spec/v0.5/extensions/economics/replay-packet.schema.json +120 -0
- package/dist/spec/v0.5/extensions/mcp/README.md +1 -1
- package/dist/spec/v0.5/memory-hierarchy.yaml +120 -0
- package/dist/spec/v1/agent-card.schema.json +254 -0
- package/dist/types/cognition.zod.d.ts +312 -0
- package/dist/types/cognition.zod.js +223 -0
- package/dist/types/identity.zod.d.ts +5 -5
- package/dist/types/index.d.ts +53 -7
- package/dist/types/index.js +4 -2
- package/dist/types/personality.zod.d.ts +3 -3
- package/dist/utils/http-client.d.ts +22 -0
- package/dist/utils/http-client.js +51 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.js +3 -0
- package/dist/utils/proxy-resolver.d.ts +36 -0
- package/dist/utils/proxy-resolver.js +59 -0
- package/dist/utils/user-agent.d.ts +11 -0
- package/dist/utils/user-agent.js +17 -0
- package/dist/validation/version-compliance.js +1 -1
- package/examples/agentscope/react-assistant/README.md +1 -1
- package/examples/agentscope/react-assistant/agent.ossa.yaml +1 -1
- package/examples/drupal/drupal-contributor-agent/.eslintrc.json +58 -0
- package/examples/drupal/drupal-contributor-agent/.prettierrc.json +10 -0
- package/examples/drupal/drupal-contributor-agent/package.json +55 -0
- package/examples/drupal/drupal-contributor-agent/src/core/index.ts +10 -0
- package/examples/drupal/drupal-contributor-agent/src/index.ts +17 -0
- package/examples/drupal/drupal-contributor-agent/src/types/index.ts +180 -0
- package/examples/drupal/drupal-contributor-agent/tsconfig.json +36 -0
- package/examples/getting-started/01-minimal-agent.ossa.yaml +1 -1
- package/examples/getting-started/02-agent-with-tools.ossa.yaml +1 -1
- package/examples/getting-started/03-agent-with-safety.ossa.yaml +1 -1
- package/examples/getting-started/04-agent-with-messaging.ossa.yaml +1 -1
- package/examples/getting-started/05-workflow-composition.ossa.yaml +1 -1
- package/examples/getting-started/hello-world-complete.ossa.yaml +1 -1
- package/examples/reference-implementations/python-client/examples/basic_usage.py +0 -0
- package/examples/reference-implementations/python-client/examples/publish_agent.py +0 -0
- package/openapi/agent-cognition-sessions.yaml +580 -0
- package/openapi/agent-crud.yaml +20 -20
- package/openapi/core/ossa-registry-api.openapi.yaml +1 -1
- package/openapi/ossa-cli-enhancements.openapi.yaml +1 -1
- package/openapi/release-automation.openapi.yaml +1 -1
- package/openapi/schemas/common/economics.yaml +98 -0
- package/openapi/uadp-asyncapi.yaml +1 -1
- package/openapi/uadp-openapi.yaml +2 -2
- package/package.json +114 -96
- package/spec/extensions/cognition.schema.json +87 -0
- package/spec/layer4-economics/duadp-examples.json +44 -0
- package/spec/v0.4/agent.schema.json +14 -0
- package/spec/v0.5/agent-builder-openapi.yaml +230 -0
- package/spec/v0.5/agent.schema.json +32 -1
- package/spec/v0.5/extensions/cognition/cognition.schema.json +78 -1
- package/spec/v0.5/extensions/economics/context-pack.schema.json +91 -0
- package/spec/v0.5/extensions/economics/execution-profile.schema.json +148 -0
- package/spec/v0.5/extensions/economics/failure-semantics.schema.json +32 -0
- package/spec/v0.5/extensions/economics/replay-packet.schema.json +120 -0
- package/spec/v0.5/extensions/mcp/README.md +1 -1
- package/spec/v0.5/memory-hierarchy.yaml +120 -0
- package/spec/v1/agent-card.schema.json +254 -0
- package/dist/adapters/a2a/__tests__/mcp-integration.spec.d.ts +0 -5
- package/dist/adapters/a2a/__tests__/mcp-integration.spec.js +0 -268
- package/dist/adapters/a2a/__tests__/mcp-transport.spec.d.ts +0 -5
- package/dist/adapters/a2a/__tests__/mcp-transport.spec.js +0 -203
- package/dist/mcp-server/__tests__/mcp-server.spec.d.ts +0 -8
- package/dist/mcp-server/__tests__/mcp-server.spec.js +0 -566
- package/dist/validation/__tests__/error-codes.test.d.ts +0 -5
- package/dist/validation/__tests__/error-codes.test.js +0 -252
- package/dist/version-management/core/version-manager.test.d.ts +0 -2
- package/dist/version-management/core/version-manager.test.js +0 -210
package/dist/mcp-server/index.js
CHANGED
|
@@ -20,38 +20,35 @@
|
|
|
20
20
|
import 'reflect-metadata';
|
|
21
21
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
22
22
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
23
|
-
import { CallToolRequestSchema,
|
|
24
|
-
import
|
|
23
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
24
|
+
import { z } from 'zod';
|
|
25
|
+
import pino from 'pino';
|
|
25
26
|
import fg from 'fast-glob';
|
|
26
27
|
import yaml from 'js-yaml';
|
|
27
|
-
import
|
|
28
|
+
import axios from 'axios';
|
|
29
|
+
import semver from 'semver';
|
|
28
30
|
import * as fs from 'node:fs';
|
|
29
31
|
import * as path from 'node:path';
|
|
30
|
-
import pino from 'pino';
|
|
31
|
-
import semver from 'semver';
|
|
32
|
-
import { z } from 'zod';
|
|
33
|
-
import { registry as convertRegistry, initializeAdapters, } from '../adapters/index.js';
|
|
34
|
-
import { getAgentTypeConfigs, getDefaultAgentKind, getDefaultAgentVersion, getDefaultDescriptionTemplate, getDefaultRoleTemplate, } from '../config/defaults.js';
|
|
35
32
|
import { container } from '../di-container.js';
|
|
36
33
|
import { ManifestRepository } from '../repositories/manifest.repository.js';
|
|
37
|
-
import {
|
|
34
|
+
import { ValidationService } from '../services/validation.service.js';
|
|
38
35
|
import { MigrationTransformService } from '../services/migration-transform.service.js';
|
|
36
|
+
import { VersionDetectionService } from '../services/version-detection.service.js';
|
|
37
|
+
import { AgentCardGenerator } from '../services/agent-card-generator.js';
|
|
39
38
|
import { RegistryService } from '../services/registry.service.js';
|
|
40
|
-
import {
|
|
41
|
-
import {
|
|
42
|
-
import { AutoGenValidator } from '../services/validators/autogen.validator.js';
|
|
43
|
-
import { CrewAIValidator } from '../services/validators/crewai.validator.js';
|
|
39
|
+
import { getApiVersion, getVersion } from '../utils/version.js';
|
|
40
|
+
import { getDefaultAgentVersion, getDefaultAgentKind, getDefaultRoleTemplate, getDefaultDescriptionTemplate, getAgentTypeConfigs, } from '../config/defaults.js';
|
|
44
41
|
import { CursorValidator } from '../services/validators/cursor.validator.js';
|
|
45
|
-
import {
|
|
42
|
+
import { OpenAIValidator } from '../services/validators/openai.validator.js';
|
|
43
|
+
import { CrewAIValidator } from '../services/validators/crewai.validator.js';
|
|
46
44
|
import { LangChainValidator } from '../services/validators/langchain.validator.js';
|
|
45
|
+
import { AnthropicValidator } from '../services/validators/anthropic.validator.js';
|
|
47
46
|
import { LangflowValidator } from '../services/validators/langflow.validator.js';
|
|
48
|
-
import {
|
|
49
|
-
import { LlamaIndexValidator } from '../services/validators/llamaindex.validator.js';
|
|
50
|
-
import { OpenAIValidator } from '../services/validators/openai.validator.js';
|
|
47
|
+
import { AutoGenValidator } from '../services/validators/autogen.validator.js';
|
|
51
48
|
import { VercelAIValidator } from '../services/validators/vercel-ai.validator.js';
|
|
52
|
-
import {
|
|
53
|
-
import {
|
|
54
|
-
import {
|
|
49
|
+
import { LlamaIndexValidator } from '../services/validators/llamaindex.validator.js';
|
|
50
|
+
import { LangGraphValidator } from '../services/validators/langgraph.validator.js';
|
|
51
|
+
import { KagentValidator } from '../services/validators/kagent.validator.js';
|
|
55
52
|
// ---------------------------------------------------------------------------
|
|
56
53
|
// Logging — pino (structured JSON to stderr so MCP stdio stays clean)
|
|
57
54
|
// ---------------------------------------------------------------------------
|
|
@@ -69,39 +66,23 @@ const ValidateInput = z.object({
|
|
|
69
66
|
path: z.string().min(1, 'path is required'),
|
|
70
67
|
platform: z
|
|
71
68
|
.enum([
|
|
72
|
-
'kagent',
|
|
73
|
-
'
|
|
74
|
-
'
|
|
75
|
-
'docker',
|
|
76
|
-
'kubernetes',
|
|
77
|
-
'gitlab-duo',
|
|
78
|
-
'anthropic',
|
|
69
|
+
'kagent', 'langchain', 'crewai', 'docker', 'kubernetes', 'gitlab-duo',
|
|
70
|
+
'anthropic', 'cursor', 'openai_agents', 'langflow', 'autogen',
|
|
71
|
+
'vercel_ai', 'llamaindex', 'langgraph',
|
|
79
72
|
])
|
|
80
73
|
.optional(),
|
|
81
74
|
strict: z.boolean().optional().default(false),
|
|
82
75
|
});
|
|
83
76
|
const ScaffoldInput = z.object({
|
|
84
|
-
name: z
|
|
85
|
-
.string()
|
|
86
|
-
.min(1)
|
|
87
|
-
.regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/, 'Must be DNS-1123 format'),
|
|
77
|
+
name: z.string().min(1).regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/, 'Must be DNS-1123 format'),
|
|
88
78
|
output_dir: z.string().optional().default('.agents'),
|
|
89
79
|
description: z.string().optional(),
|
|
90
80
|
role: z.string().optional(),
|
|
91
81
|
type: z
|
|
92
|
-
.enum([
|
|
93
|
-
'worker',
|
|
94
|
-
'orchestrator',
|
|
95
|
-
'reviewer',
|
|
96
|
-
'analyzer',
|
|
97
|
-
'executor',
|
|
98
|
-
'approver',
|
|
99
|
-
])
|
|
82
|
+
.enum(['worker', 'orchestrator', 'reviewer', 'analyzer', 'executor', 'approver'])
|
|
100
83
|
.optional()
|
|
101
84
|
.default('worker'),
|
|
102
85
|
version: z.string().optional(),
|
|
103
|
-
source_project_id: z.string().optional(),
|
|
104
|
-
execution_node_id: z.string().optional(),
|
|
105
86
|
});
|
|
106
87
|
const GenerateInput = z.object({
|
|
107
88
|
path: z.string().min(1, 'path is required'),
|
|
@@ -134,7 +115,6 @@ const ConvertInput = z.object({
|
|
|
134
115
|
'semantic-kernel',
|
|
135
116
|
'a2a',
|
|
136
117
|
'agent-card',
|
|
137
|
-
'claude-agent-sdk',
|
|
138
118
|
]),
|
|
139
119
|
output_dir: z.string().optional(),
|
|
140
120
|
});
|
|
@@ -161,8 +141,6 @@ const migrationTransformService = container.get(MigrationTransformService);
|
|
|
161
141
|
const versionDetectionService = container.get(VersionDetectionService);
|
|
162
142
|
const registryService = container.get(RegistryService);
|
|
163
143
|
const agentCardGenerator = new AgentCardGenerator();
|
|
164
|
-
// Initialize adapter registry (config-only adapters for MCP convert)
|
|
165
|
-
initializeAdapters();
|
|
166
144
|
// ---------------------------------------------------------------------------
|
|
167
145
|
// MCP Server
|
|
168
146
|
// ---------------------------------------------------------------------------
|
|
@@ -184,28 +162,17 @@ const tools = [
|
|
|
184
162
|
inputSchema: {
|
|
185
163
|
type: 'object',
|
|
186
164
|
properties: {
|
|
187
|
-
path: {
|
|
188
|
-
type: 'string',
|
|
189
|
-
description: 'Path to manifest file (.ossa.yaml, .ossa.yml, .json)',
|
|
190
|
-
},
|
|
165
|
+
path: { type: 'string', description: 'Path to manifest file (.ossa.yaml, .ossa.yml, .json)' },
|
|
191
166
|
platform: {
|
|
192
167
|
type: 'string',
|
|
193
168
|
enum: [
|
|
194
|
-
'kagent',
|
|
195
|
-
'
|
|
196
|
-
'
|
|
197
|
-
'docker',
|
|
198
|
-
'kubernetes',
|
|
199
|
-
'gitlab-duo',
|
|
200
|
-
'anthropic',
|
|
169
|
+
'kagent', 'langchain', 'crewai', 'docker', 'kubernetes', 'gitlab-duo',
|
|
170
|
+
'anthropic', 'cursor', 'openai_agents', 'langflow', 'autogen',
|
|
171
|
+
'vercel_ai', 'llamaindex', 'langgraph',
|
|
201
172
|
],
|
|
202
|
-
description: 'Optional platform-specific validation',
|
|
203
|
-
},
|
|
204
|
-
strict: {
|
|
205
|
-
type: 'boolean',
|
|
206
|
-
description: 'Enable strict mode (warnings become errors)',
|
|
207
|
-
default: false,
|
|
173
|
+
description: 'Optional platform-specific validation (runs targeted validator for this platform)',
|
|
208
174
|
},
|
|
175
|
+
strict: { type: 'boolean', description: 'Enable strict mode (warnings become errors)', default: false },
|
|
209
176
|
},
|
|
210
177
|
required: ['path'],
|
|
211
178
|
},
|
|
@@ -216,33 +183,16 @@ const tools = [
|
|
|
216
183
|
inputSchema: {
|
|
217
184
|
type: 'object',
|
|
218
185
|
properties: {
|
|
219
|
-
name: {
|
|
220
|
-
|
|
221
|
-
description: 'Agent name (DNS-1123: lowercase alphanumeric + hyphens)',
|
|
222
|
-
},
|
|
223
|
-
output_dir: {
|
|
224
|
-
type: 'string',
|
|
225
|
-
description: 'Parent directory (default: .agents)',
|
|
226
|
-
default: '.agents',
|
|
227
|
-
},
|
|
186
|
+
name: { type: 'string', description: 'Agent name (DNS-1123: lowercase alphanumeric + hyphens)' },
|
|
187
|
+
output_dir: { type: 'string', description: 'Parent directory (default: .agents)', default: '.agents' },
|
|
228
188
|
description: { type: 'string', description: 'Short description' },
|
|
229
189
|
role: { type: 'string', description: 'System prompt / role' },
|
|
230
190
|
type: {
|
|
231
191
|
type: 'string',
|
|
232
|
-
enum: [
|
|
233
|
-
'worker',
|
|
234
|
-
'orchestrator',
|
|
235
|
-
'reviewer',
|
|
236
|
-
'analyzer',
|
|
237
|
-
'executor',
|
|
238
|
-
'approver',
|
|
239
|
-
],
|
|
192
|
+
enum: ['worker', 'orchestrator', 'reviewer', 'analyzer', 'executor', 'approver'],
|
|
240
193
|
default: 'worker',
|
|
241
194
|
},
|
|
242
|
-
version: {
|
|
243
|
-
type: 'string',
|
|
244
|
-
description: 'Initial version (default: 1.0.0)',
|
|
245
|
-
},
|
|
195
|
+
version: { type: 'string', description: 'Initial version (default: 1.0.0)' },
|
|
246
196
|
},
|
|
247
197
|
required: ['name'],
|
|
248
198
|
},
|
|
@@ -254,10 +204,7 @@ const tools = [
|
|
|
254
204
|
type: 'object',
|
|
255
205
|
properties: {
|
|
256
206
|
path: { type: 'string', description: 'Path to OSSA manifest file' },
|
|
257
|
-
output_dir: {
|
|
258
|
-
type: 'string',
|
|
259
|
-
description: 'Optional directory to write agent-card.json',
|
|
260
|
-
},
|
|
207
|
+
output_dir: { type: 'string', description: 'Optional directory to write agent-card.json' },
|
|
261
208
|
},
|
|
262
209
|
required: ['path'],
|
|
263
210
|
},
|
|
@@ -269,15 +216,8 @@ const tools = [
|
|
|
269
216
|
type: 'object',
|
|
270
217
|
properties: {
|
|
271
218
|
path: { type: 'string', description: 'Path to OSSA manifest file' },
|
|
272
|
-
registry_url: {
|
|
273
|
-
|
|
274
|
-
description: 'Registry base URL (or set REGISTRY_URL / AGENT_REGISTRY_URL env)',
|
|
275
|
-
},
|
|
276
|
-
dry_run: {
|
|
277
|
-
type: 'boolean',
|
|
278
|
-
description: 'Preview publish payload without sending',
|
|
279
|
-
default: false,
|
|
280
|
-
},
|
|
219
|
+
registry_url: { type: 'string', description: 'Registry base URL (or set REGISTRY_URL / AGENT_REGISTRY_URL env)' },
|
|
220
|
+
dry_run: { type: 'boolean', description: 'Preview publish payload without sending', default: false },
|
|
281
221
|
},
|
|
282
222
|
required: ['path'],
|
|
283
223
|
},
|
|
@@ -288,16 +228,8 @@ const tools = [
|
|
|
288
228
|
inputSchema: {
|
|
289
229
|
type: 'object',
|
|
290
230
|
properties: {
|
|
291
|
-
directory: {
|
|
292
|
-
|
|
293
|
-
description: 'Root directory to scan (default: cwd)',
|
|
294
|
-
default: '.',
|
|
295
|
-
},
|
|
296
|
-
recursive: {
|
|
297
|
-
type: 'boolean',
|
|
298
|
-
description: 'Scan subdirectories',
|
|
299
|
-
default: true,
|
|
300
|
-
},
|
|
231
|
+
directory: { type: 'string', description: 'Root directory to scan (default: cwd)', default: '.' },
|
|
232
|
+
recursive: { type: 'boolean', description: 'Scan subdirectories', default: true },
|
|
301
233
|
format: {
|
|
302
234
|
type: 'string',
|
|
303
235
|
enum: ['summary', 'detailed', 'json'],
|
|
@@ -327,25 +259,10 @@ const tools = [
|
|
|
327
259
|
path: { type: 'string', description: 'Path to OSSA manifest file' },
|
|
328
260
|
target: {
|
|
329
261
|
type: 'string',
|
|
330
|
-
enum: [
|
|
331
|
-
'kagent',
|
|
332
|
-
'docker',
|
|
333
|
-
'langchain',
|
|
334
|
-
'crewai',
|
|
335
|
-
'gitlab-duo',
|
|
336
|
-
'anthropic',
|
|
337
|
-
'openai',
|
|
338
|
-
'autogen',
|
|
339
|
-
'semantic-kernel',
|
|
340
|
-
'a2a',
|
|
341
|
-
'agent-card',
|
|
342
|
-
],
|
|
262
|
+
enum: ['kagent', 'docker', 'langchain', 'crewai', 'gitlab-duo', 'anthropic', 'openai', 'autogen', 'semantic-kernel', 'a2a', 'agent-card'],
|
|
343
263
|
description: 'Target format',
|
|
344
264
|
},
|
|
345
|
-
output_dir: {
|
|
346
|
-
type: 'string',
|
|
347
|
-
description: 'Optional directory to write converted output',
|
|
348
|
-
},
|
|
265
|
+
output_dir: { type: 'string', description: 'Optional directory to write converted output' },
|
|
349
266
|
},
|
|
350
267
|
required: ['path', 'target'],
|
|
351
268
|
},
|
|
@@ -361,10 +278,7 @@ const tools = [
|
|
|
361
278
|
enum: ['init', 'discover', 'status'],
|
|
362
279
|
description: 'Workspace action',
|
|
363
280
|
},
|
|
364
|
-
directory: {
|
|
365
|
-
type: 'string',
|
|
366
|
-
description: 'Root directory to scan (default: current dir)',
|
|
367
|
-
},
|
|
281
|
+
directory: { type: 'string', description: 'Root directory to scan (default: current dir)' },
|
|
368
282
|
name: { type: 'string', description: 'Workspace name (for init)' },
|
|
369
283
|
},
|
|
370
284
|
required: ['action'],
|
|
@@ -394,10 +308,7 @@ const tools = [
|
|
|
394
308
|
description: 'Target OSSA version (default: ossa/v0.4)',
|
|
395
309
|
default: 'ossa/v0.4',
|
|
396
310
|
},
|
|
397
|
-
output_dir: {
|
|
398
|
-
type: 'string',
|
|
399
|
-
description: 'Optional directory to write migrated manifest',
|
|
400
|
-
},
|
|
311
|
+
output_dir: { type: 'string', description: 'Optional directory to write migrated manifest' },
|
|
401
312
|
},
|
|
402
313
|
required: ['path'],
|
|
403
314
|
},
|
|
@@ -451,20 +362,11 @@ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
|
451
362
|
const schemaContent = fs.existsSync(schemaPath)
|
|
452
363
|
? fs.readFileSync(schemaPath, 'utf8')
|
|
453
364
|
: JSON.stringify({ error: 'Schema file not found', path: schemaPath });
|
|
454
|
-
return {
|
|
455
|
-
contents: [
|
|
456
|
-
{
|
|
457
|
-
uri: request.params.uri,
|
|
458
|
-
mimeType: 'application/schema+json',
|
|
459
|
-
text: schemaContent,
|
|
460
|
-
},
|
|
461
|
-
],
|
|
462
|
-
};
|
|
365
|
+
return { contents: [{ uri: request.params.uri, mimeType: 'application/schema+json', text: schemaContent }] };
|
|
463
366
|
}
|
|
464
367
|
case 'ossa://template/minimal':
|
|
465
368
|
return {
|
|
466
|
-
contents: [
|
|
467
|
-
{
|
|
369
|
+
contents: [{
|
|
468
370
|
uri: request.params.uri,
|
|
469
371
|
mimeType: 'text/yaml',
|
|
470
372
|
text: `apiVersion: ossa/v0.4
|
|
@@ -476,13 +378,11 @@ metadata:
|
|
|
476
378
|
spec:
|
|
477
379
|
role: You are a helpful assistant.
|
|
478
380
|
`,
|
|
479
|
-
},
|
|
480
|
-
],
|
|
381
|
+
}],
|
|
481
382
|
};
|
|
482
383
|
case 'ossa://template/full':
|
|
483
384
|
return {
|
|
484
|
-
contents: [
|
|
485
|
-
{
|
|
385
|
+
contents: [{
|
|
486
386
|
uri: request.params.uri,
|
|
487
387
|
mimeType: 'text/yaml',
|
|
488
388
|
text: `apiVersion: ossa/v0.4
|
|
@@ -576,13 +476,11 @@ token_efficiency:
|
|
|
576
476
|
- model: claude-sonnet-4-20250514
|
|
577
477
|
max_tokens: 4096
|
|
578
478
|
`,
|
|
579
|
-
},
|
|
580
|
-
],
|
|
479
|
+
}],
|
|
581
480
|
};
|
|
582
481
|
case 'ossa://guide/mcp-ossa-a2a':
|
|
583
482
|
return {
|
|
584
|
-
contents: [
|
|
585
|
-
{
|
|
483
|
+
contents: [{
|
|
586
484
|
uri: request.params.uri,
|
|
587
485
|
mimeType: 'text/markdown',
|
|
588
486
|
text: `# MCP → OSSA → A2A: The Agent Stack
|
|
@@ -650,150 +548,34 @@ npx ossa convert .agents/my-agent/manifest.ossa.yaml --target agent-card
|
|
|
650
548
|
- npm: https://www.npmjs.com/package/@bluefly/openstandardagents
|
|
651
549
|
- MCP Server: \`npx ossa-mcp\` (this server)
|
|
652
550
|
`,
|
|
653
|
-
},
|
|
654
|
-
],
|
|
551
|
+
}],
|
|
655
552
|
};
|
|
656
553
|
case 'ossa://platforms/supported':
|
|
657
554
|
return {
|
|
658
|
-
contents: [
|
|
659
|
-
{
|
|
555
|
+
contents: [{
|
|
660
556
|
uri: request.params.uri,
|
|
661
557
|
mimeType: 'application/json',
|
|
662
558
|
text: JSON.stringify({
|
|
663
559
|
platforms: [
|
|
664
|
-
{
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
},
|
|
671
|
-
{
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
},
|
|
678
|
-
{
|
|
679
|
-
id: 'openai',
|
|
680
|
-
name: 'OpenAI',
|
|
681
|
-
type: 'llm',
|
|
682
|
-
sdk: { npm: 'openai', pip: 'openai' },
|
|
683
|
-
docs: 'https://platform.openai.com/docs',
|
|
684
|
-
format: 'Assistants / function_calling',
|
|
685
|
-
},
|
|
686
|
-
{
|
|
687
|
-
id: 'anthropic',
|
|
688
|
-
name: 'Anthropic',
|
|
689
|
-
type: 'llm',
|
|
690
|
-
sdk: { npm: '@anthropic-ai/sdk', pip: 'anthropic' },
|
|
691
|
-
docs: 'https://docs.anthropic.com',
|
|
692
|
-
format: 'Messages API + tool_use',
|
|
693
|
-
},
|
|
694
|
-
{
|
|
695
|
-
id: 'google_genai',
|
|
696
|
-
name: 'Google Gemini',
|
|
697
|
-
type: 'llm',
|
|
698
|
-
sdk: {
|
|
699
|
-
npm: '@google/generative-ai',
|
|
700
|
-
pip: 'google-generativeai',
|
|
701
|
-
},
|
|
702
|
-
docs: 'https://ai.google.dev',
|
|
703
|
-
format: 'GenerativeAI',
|
|
704
|
-
},
|
|
705
|
-
{
|
|
706
|
-
id: 'langchain',
|
|
707
|
-
name: 'LangChain',
|
|
708
|
-
type: 'framework',
|
|
709
|
-
sdk: {
|
|
710
|
-
npm: ['langchain', '@langchain/core'],
|
|
711
|
-
pip: ['langchain', 'langchain-openai'],
|
|
712
|
-
},
|
|
713
|
-
docs: 'https://js.langchain.com',
|
|
714
|
-
format: 'Agent + StructuredTool',
|
|
715
|
-
},
|
|
716
|
-
{
|
|
717
|
-
id: 'langflow',
|
|
718
|
-
name: 'LangFlow',
|
|
719
|
-
type: 'visual',
|
|
720
|
-
sdk: { pip: 'langflow' },
|
|
721
|
-
docs: 'https://docs.langflow.org',
|
|
722
|
-
format: 'Custom component',
|
|
723
|
-
},
|
|
724
|
-
{
|
|
725
|
-
id: 'crewai',
|
|
726
|
-
name: 'CrewAI',
|
|
727
|
-
type: 'framework',
|
|
728
|
-
sdk: { pip: 'crewai' },
|
|
729
|
-
docs: 'https://docs.crewai.com',
|
|
730
|
-
format: 'Agent YAML',
|
|
731
|
-
},
|
|
732
|
-
{
|
|
733
|
-
id: 'autogen',
|
|
734
|
-
name: 'AutoGen',
|
|
735
|
-
type: 'framework',
|
|
736
|
-
sdk: { pip: 'autogen-agentchat' },
|
|
737
|
-
docs: 'https://microsoft.github.io/autogen',
|
|
738
|
-
format: 'ConversableAgent',
|
|
739
|
-
},
|
|
740
|
-
{
|
|
741
|
-
id: 'semantic-kernel',
|
|
742
|
-
name: 'Semantic Kernel',
|
|
743
|
-
type: 'framework',
|
|
744
|
-
sdk: { npm: 'semantic-kernel', pip: 'semantic-kernel' },
|
|
745
|
-
docs: 'https://learn.microsoft.com/en-us/semantic-kernel',
|
|
746
|
-
format: 'Agent + Plugins',
|
|
747
|
-
},
|
|
748
|
-
{
|
|
749
|
-
id: 'llamaindex',
|
|
750
|
-
name: 'LlamaIndex',
|
|
751
|
-
type: 'framework',
|
|
752
|
-
sdk: { npm: 'llamaindex', pip: 'llama-index' },
|
|
753
|
-
docs: 'https://docs.llamaindex.ai',
|
|
754
|
-
format: 'Agent config',
|
|
755
|
-
},
|
|
756
|
-
{
|
|
757
|
-
id: 'dspy',
|
|
758
|
-
name: 'DSPy',
|
|
759
|
-
type: 'framework',
|
|
760
|
-
sdk: { pip: 'dspy' },
|
|
761
|
-
docs: 'https://dspy.ai',
|
|
762
|
-
format: 'Module config',
|
|
763
|
-
},
|
|
764
|
-
{
|
|
765
|
-
id: 'gitlab-duo',
|
|
766
|
-
name: 'GitLab Duo',
|
|
767
|
-
type: 'devops',
|
|
768
|
-
docs: 'https://docs.gitlab.com/ee/user/gitlab_duo',
|
|
769
|
-
format: 'Duo agent YAML',
|
|
770
|
-
},
|
|
771
|
-
{
|
|
772
|
-
id: 'agent-card',
|
|
773
|
-
name: 'Universal Agent Card',
|
|
774
|
-
type: 'universal',
|
|
775
|
-
docs: 'https://openstandardagents.org',
|
|
776
|
-
format: 'Cross-platform JSON with all 12 adapters',
|
|
777
|
-
},
|
|
778
|
-
{
|
|
779
|
-
id: 'claude-agent-sdk',
|
|
780
|
-
name: 'Claude Agent SDK',
|
|
781
|
-
type: 'agent-sdk',
|
|
782
|
-
sdk: {
|
|
783
|
-
npm: '@anthropic-ai/claude-agent-sdk',
|
|
784
|
-
pip: 'claude-agent-sdk',
|
|
785
|
-
go: 'github.com/M1n9X/claude-agent-sdk-go',
|
|
786
|
-
rust: 'claude_agent',
|
|
787
|
-
},
|
|
788
|
-
docs: 'https://docs.claude.com/en/api/agent-sdk/overview',
|
|
789
|
-
format: 'Runnable Agent SDK app (TS/PY/Go/Rust)',
|
|
790
|
-
},
|
|
560
|
+
{ id: 'kagent', name: 'kagent.dev', type: 'kubernetes', docs: 'https://kagent.dev', format: 'v1alpha2 CRD (Agent + ModelConfig)' },
|
|
561
|
+
{ id: 'docker', name: 'Docker', type: 'container', docs: 'https://docs.docker.com', format: 'docker-compose.yml' },
|
|
562
|
+
{ id: 'openai', name: 'OpenAI', type: 'llm', sdk: { npm: 'openai', pip: 'openai' }, docs: 'https://platform.openai.com/docs', format: 'Assistants / function_calling' },
|
|
563
|
+
{ id: 'anthropic', name: 'Anthropic', type: 'llm', sdk: { npm: '@anthropic-ai/sdk', pip: 'anthropic' }, docs: 'https://docs.anthropic.com', format: 'Messages API + tool_use' },
|
|
564
|
+
{ id: 'google_genai', name: 'Google Gemini', type: 'llm', sdk: { npm: '@google/generative-ai', pip: 'google-generativeai' }, docs: 'https://ai.google.dev', format: 'GenerativeAI' },
|
|
565
|
+
{ id: 'langchain', name: 'LangChain', type: 'framework', sdk: { npm: ['langchain', '@langchain/core'], pip: ['langchain', 'langchain-openai'] }, docs: 'https://js.langchain.com', format: 'Agent + StructuredTool' },
|
|
566
|
+
{ id: 'langflow', name: 'LangFlow', type: 'visual', sdk: { pip: 'langflow' }, docs: 'https://docs.langflow.org', format: 'Custom component' },
|
|
567
|
+
{ id: 'crewai', name: 'CrewAI', type: 'framework', sdk: { pip: 'crewai' }, docs: 'https://docs.crewai.com', format: 'Agent YAML' },
|
|
568
|
+
{ id: 'autogen', name: 'AutoGen', type: 'framework', sdk: { pip: 'autogen-agentchat' }, docs: 'https://microsoft.github.io/autogen', format: 'ConversableAgent' },
|
|
569
|
+
{ id: 'semantic-kernel', name: 'Semantic Kernel', type: 'framework', sdk: { npm: 'semantic-kernel', pip: 'semantic-kernel' }, docs: 'https://learn.microsoft.com/en-us/semantic-kernel', format: 'Agent + Plugins' },
|
|
570
|
+
{ id: 'llamaindex', name: 'LlamaIndex', type: 'framework', sdk: { npm: 'llamaindex', pip: 'llama-index' }, docs: 'https://docs.llamaindex.ai', format: 'Agent config' },
|
|
571
|
+
{ id: 'dspy', name: 'DSPy', type: 'framework', sdk: { pip: 'dspy' }, docs: 'https://dspy.ai', format: 'Module config' },
|
|
572
|
+
{ id: 'gitlab-duo', name: 'GitLab Duo', type: 'devops', docs: 'https://docs.gitlab.com/ee/user/gitlab_duo', format: 'Duo agent YAML' },
|
|
573
|
+
{ id: 'agent-card', name: 'Universal Agent Card', type: 'universal', docs: 'https://openstandardagents.org', format: 'Cross-platform JSON with all 12 adapters' },
|
|
791
574
|
],
|
|
792
|
-
total:
|
|
575
|
+
total: 14,
|
|
793
576
|
ossa_version: 'ossa/v0.4',
|
|
794
577
|
}, null, 2),
|
|
795
|
-
},
|
|
796
|
-
],
|
|
578
|
+
}],
|
|
797
579
|
};
|
|
798
580
|
default:
|
|
799
581
|
throw new Error(`Unknown resource: ${request.params.uri}`);
|
|
@@ -808,16 +590,8 @@ server.setRequestHandler(ListPromptsRequestSchema, async () => ({
|
|
|
808
590
|
name: 'create-agent',
|
|
809
591
|
description: 'Create a new OSSA agent from a description of what it should do',
|
|
810
592
|
arguments: [
|
|
811
|
-
{
|
|
812
|
-
|
|
813
|
-
description: 'What the agent should do',
|
|
814
|
-
required: true,
|
|
815
|
-
},
|
|
816
|
-
{
|
|
817
|
-
name: 'name',
|
|
818
|
-
description: 'Agent name (DNS-1123 format)',
|
|
819
|
-
required: false,
|
|
820
|
-
},
|
|
593
|
+
{ name: 'description', description: 'What the agent should do', required: true },
|
|
594
|
+
{ name: 'name', description: 'Agent name (DNS-1123 format)', required: false },
|
|
821
595
|
],
|
|
822
596
|
},
|
|
823
597
|
{
|
|
@@ -846,8 +620,7 @@ server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
|
846
620
|
case 'create-agent':
|
|
847
621
|
return {
|
|
848
622
|
description: 'Create a new OSSA agent',
|
|
849
|
-
messages: [
|
|
850
|
-
{
|
|
623
|
+
messages: [{
|
|
851
624
|
role: 'user',
|
|
852
625
|
content: {
|
|
853
626
|
type: 'text',
|
|
@@ -857,14 +630,12 @@ Use the ossa_scaffold tool to create the directory structure, then customize the
|
|
|
857
630
|
|
|
858
631
|
After scaffolding, read the manifest, customize it with appropriate tools, capabilities, and LLM config, then validate it with ossa_validate.`,
|
|
859
632
|
},
|
|
860
|
-
},
|
|
861
|
-
],
|
|
633
|
+
}],
|
|
862
634
|
};
|
|
863
635
|
case 'convert-for-platform':
|
|
864
636
|
return {
|
|
865
637
|
description: 'Convert manifest to target platform',
|
|
866
|
-
messages: [
|
|
867
|
-
{
|
|
638
|
+
messages: [{
|
|
868
639
|
role: 'user',
|
|
869
640
|
content: {
|
|
870
641
|
type: 'text',
|
|
@@ -872,14 +643,12 @@ After scaffolding, read the manifest, customize it with appropriate tools, capab
|
|
|
872
643
|
|
|
873
644
|
Use ossa_convert with the target platform. If converting to agent-card, explain the cross-platform adapters available (OpenAI, Anthropic, LangChain, CrewAI, etc.) and the SDK packages needed.`,
|
|
874
645
|
},
|
|
875
|
-
},
|
|
876
|
-
],
|
|
646
|
+
}],
|
|
877
647
|
};
|
|
878
648
|
case 'explain-manifest':
|
|
879
649
|
return {
|
|
880
650
|
description: 'Explain an OSSA manifest',
|
|
881
|
-
messages: [
|
|
882
|
-
{
|
|
651
|
+
messages: [{
|
|
883
652
|
role: 'user',
|
|
884
653
|
content: {
|
|
885
654
|
type: 'text',
|
|
@@ -890,14 +659,12 @@ Use ossa_convert with the target platform. If converting to agent-card, explain
|
|
|
890
659
|
4. Its autonomy level and safety constraints
|
|
891
660
|
5. How it can be deployed (platforms it supports)`,
|
|
892
661
|
},
|
|
893
|
-
},
|
|
894
|
-
],
|
|
662
|
+
}],
|
|
895
663
|
};
|
|
896
664
|
case 'what-is-ossa':
|
|
897
665
|
return {
|
|
898
666
|
description: 'Explain OSSA',
|
|
899
|
-
messages: [
|
|
900
|
-
{
|
|
667
|
+
messages: [{
|
|
901
668
|
role: 'user',
|
|
902
669
|
content: {
|
|
903
670
|
type: 'text',
|
|
@@ -910,8 +677,7 @@ Read the ossa://guide/mcp-ossa-a2a resource for the full explanation. Key points
|
|
|
910
677
|
|
|
911
678
|
Show the supported platforms using the ossa://platforms/supported resource.`,
|
|
912
679
|
},
|
|
913
|
-
},
|
|
914
|
-
],
|
|
680
|
+
}],
|
|
915
681
|
};
|
|
916
682
|
default:
|
|
917
683
|
throw new Error(`Unknown prompt: ${request.params.name}`);
|
|
@@ -1006,10 +772,7 @@ async function handleValidate(args) {
|
|
|
1006
772
|
}
|
|
1007
773
|
// Merge platform results into base results
|
|
1008
774
|
if (platformErrors.length) {
|
|
1009
|
-
result.errors = [
|
|
1010
|
-
...(result.errors || []),
|
|
1011
|
-
...platformErrors,
|
|
1012
|
-
];
|
|
775
|
+
result.errors = [...(result.errors || []), ...platformErrors];
|
|
1013
776
|
result.valid = false;
|
|
1014
777
|
}
|
|
1015
778
|
if (platformWarnings.length) {
|
|
@@ -1020,10 +783,7 @@ async function handleValidate(args) {
|
|
|
1020
783
|
// Strict mode: promote warnings to errors
|
|
1021
784
|
if (input.strict && result.warnings?.length) {
|
|
1022
785
|
const promoted = result.warnings.map((w) => `[strict] ${w}`);
|
|
1023
|
-
result.errors = [
|
|
1024
|
-
...(result.errors || []),
|
|
1025
|
-
...promoted,
|
|
1026
|
-
];
|
|
786
|
+
result.errors = [...(result.errors || []), ...promoted];
|
|
1027
787
|
result.valid = !result.errors?.length;
|
|
1028
788
|
}
|
|
1029
789
|
return okResponse({
|
|
@@ -1032,13 +792,11 @@ async function handleValidate(args) {
|
|
|
1032
792
|
warnings: result.warnings || [],
|
|
1033
793
|
manifest_path: manifestPath,
|
|
1034
794
|
platform: input.platform || null,
|
|
1035
|
-
platform_validation: input.platform
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
}
|
|
1041
|
-
: undefined,
|
|
795
|
+
platform_validation: input.platform ? {
|
|
796
|
+
platform: input.platform,
|
|
797
|
+
errors: platformErrors,
|
|
798
|
+
warnings: platformWarnings,
|
|
799
|
+
} : undefined,
|
|
1042
800
|
});
|
|
1043
801
|
}
|
|
1044
802
|
// ---------------------------------------------------------------------------
|
|
@@ -1060,17 +818,11 @@ async function handleScaffold(args) {
|
|
|
1060
818
|
name: input.name,
|
|
1061
819
|
version: input.version || getDefaultAgentVersion(),
|
|
1062
820
|
description: input.description || getDefaultDescriptionTemplate(input.name),
|
|
1063
|
-
mesh_bindings: {
|
|
1064
|
-
source_project_id: input.source_project_id || process.env.OSSA_DEFAULT_SOURCE_PROJECT_ID || '',
|
|
1065
|
-
execution_node_id: input.execution_node_id || process.env.OSSA_DEFAULT_EXECUTION_NODE_ID || '',
|
|
1066
|
-
},
|
|
1067
821
|
},
|
|
1068
822
|
spec: {
|
|
1069
823
|
role: input.role || getDefaultRoleTemplate(input.name),
|
|
1070
824
|
llm: { provider: 'openai', model: '${LLM_MODEL:-gpt-4}' },
|
|
1071
|
-
tools: typeConfig.capabilityName
|
|
1072
|
-
? [{ type: 'capability', name: typeConfig.capabilityName }]
|
|
1073
|
-
: [],
|
|
825
|
+
tools: typeConfig.capabilityName ? [{ type: 'capability', name: typeConfig.capabilityName }] : [],
|
|
1074
826
|
},
|
|
1075
827
|
};
|
|
1076
828
|
// Create directory structure
|
|
@@ -1108,11 +860,7 @@ async function handleGenerate(args) {
|
|
|
1108
860
|
fs.mkdirSync(wellKnown, { recursive: true });
|
|
1109
861
|
const cardPath = path.join(wellKnown, 'agent-card.json');
|
|
1110
862
|
fs.writeFileSync(cardPath, result.json ?? JSON.stringify(result.card, null, 2), 'utf8');
|
|
1111
|
-
return okResponse({
|
|
1112
|
-
success: true,
|
|
1113
|
-
agent_card: result.card,
|
|
1114
|
-
written_to: cardPath,
|
|
1115
|
-
});
|
|
863
|
+
return okResponse({ success: true, agent_card: result.card, written_to: cardPath });
|
|
1116
864
|
}
|
|
1117
865
|
return okResponse({ success: true, agent_card: result.card });
|
|
1118
866
|
}
|
|
@@ -1131,9 +879,7 @@ async function handlePublish(args) {
|
|
|
1131
879
|
};
|
|
1132
880
|
// Dry run — show what would happen for both local and remote
|
|
1133
881
|
if (input.dry_run) {
|
|
1134
|
-
const registryUrl = input.registry_url ||
|
|
1135
|
-
process.env.REGISTRY_URL ||
|
|
1136
|
-
process.env.AGENT_REGISTRY_URL;
|
|
882
|
+
const registryUrl = input.registry_url || process.env.REGISTRY_URL || process.env.AGENT_REGISTRY_URL;
|
|
1137
883
|
return okResponse({
|
|
1138
884
|
dry_run: true,
|
|
1139
885
|
payload,
|
|
@@ -1143,10 +889,7 @@ async function handlePublish(args) {
|
|
|
1143
889
|
version: manifest.metadata?.version || '1.0.0',
|
|
1144
890
|
},
|
|
1145
891
|
remote_publish: registryUrl
|
|
1146
|
-
? {
|
|
1147
|
-
registry_url: registryUrl,
|
|
1148
|
-
url: registryUrl.replace(/\/?$/, '/api/v1/agents'),
|
|
1149
|
-
}
|
|
892
|
+
? { registry_url: registryUrl, url: registryUrl.replace(/\/?$/, '/api/v1/agents') }
|
|
1150
893
|
: null,
|
|
1151
894
|
message: 'Payload that would be sent to local and/or remote registry',
|
|
1152
895
|
});
|
|
@@ -1173,9 +916,7 @@ async function handlePublish(args) {
|
|
|
1173
916
|
error: err instanceof Error ? err.message : String(err),
|
|
1174
917
|
};
|
|
1175
918
|
}
|
|
1176
|
-
const registryUrl = input.registry_url ||
|
|
1177
|
-
process.env.REGISTRY_URL ||
|
|
1178
|
-
process.env.AGENT_REGISTRY_URL;
|
|
919
|
+
const registryUrl = input.registry_url || process.env.REGISTRY_URL || process.env.AGENT_REGISTRY_URL;
|
|
1179
920
|
// Remote HTTP registry (if configured)
|
|
1180
921
|
if (registryUrl) {
|
|
1181
922
|
const url = registryUrl.replace(/\/?$/, '/api/v1/agents');
|
|
@@ -1186,74 +927,66 @@ async function handlePublish(args) {
|
|
|
1186
927
|
});
|
|
1187
928
|
return okResponse({
|
|
1188
929
|
success: res.status >= 200 && res.status < 300,
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
const arctl = spawnSync('arctl', ['publish', manifestPath], {
|
|
1197
|
-
encoding: 'utf8',
|
|
1198
|
-
timeout: 30000,
|
|
1199
|
-
});
|
|
1200
|
-
if (arctl.status === 0) {
|
|
1201
|
-
return okResponse({
|
|
1202
|
-
success: true,
|
|
1203
|
-
method: 'arctl',
|
|
1204
|
-
stdout: arctl.stdout?.trim(),
|
|
1205
|
-
local_publish: localResult,
|
|
1206
|
-
});
|
|
1207
|
-
}
|
|
1208
|
-
// No remote configured — return local result
|
|
1209
|
-
if (localResult?.success) {
|
|
1210
|
-
return okResponse({
|
|
1211
|
-
success: true,
|
|
1212
|
-
method: 'local',
|
|
1213
|
-
local_publish: localResult,
|
|
1214
|
-
message: 'Published to local registry. Set REGISTRY_URL for remote publish.',
|
|
930
|
+
local: localResult,
|
|
931
|
+
remote: {
|
|
932
|
+
success: res.status >= 200 && res.status < 300,
|
|
933
|
+
status: res.status,
|
|
934
|
+
registry_url: registryUrl,
|
|
935
|
+
data: res.data,
|
|
936
|
+
},
|
|
1215
937
|
});
|
|
1216
938
|
}
|
|
939
|
+
// No remote registry — return local result only
|
|
1217
940
|
return okResponse({
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
'Set REGISTRY_URL
|
|
1223
|
-
'
|
|
1224
|
-
'Then: arctl publish ' + manifestPath,
|
|
1225
|
-
],
|
|
941
|
+
success: localResult?.success === true,
|
|
942
|
+
local: localResult,
|
|
943
|
+
remote: null,
|
|
944
|
+
message: localResult?.success
|
|
945
|
+
? 'Published to local registry. Set REGISTRY_URL for remote publishing.'
|
|
946
|
+
: 'Local publish failed. Set REGISTRY_URL for remote publishing.',
|
|
1226
947
|
});
|
|
1227
948
|
}
|
|
1228
949
|
// ---------------------------------------------------------------------------
|
|
1229
|
-
// ossa_list — workspace discovery via
|
|
1230
|
-
//
|
|
950
|
+
// ossa_list — workspace discovery via fast-glob
|
|
951
|
+
// HACK: Inline fast-glob scan instead of AgentsMdDiscoveryService.
|
|
952
|
+
// The DI service does heavier work (repo analysis, AGENTS.md generation)
|
|
953
|
+
// that we don't need for a simple MCP list response.
|
|
954
|
+
// TODO(#443): Extract lightweight scan into a shared utility.
|
|
1231
955
|
// ---------------------------------------------------------------------------
|
|
1232
956
|
async function handleList(args) {
|
|
1233
957
|
const input = ListInput.parse(args);
|
|
1234
958
|
const baseDir = resolvePath(input.directory);
|
|
1235
|
-
const
|
|
1236
|
-
|
|
1237
|
-
|
|
959
|
+
const patterns = input.recursive
|
|
960
|
+
? ['**/*.ossa.yaml', '**/*.ossa.yml', '**/.agents/*/manifest.ossa.yaml']
|
|
961
|
+
: ['*.ossa.yaml', '*.ossa.yml', '.agents/*/manifest.ossa.yaml'];
|
|
962
|
+
const files = await fg(patterns, {
|
|
963
|
+
cwd: baseDir,
|
|
1238
964
|
absolute: true,
|
|
965
|
+
ignore: ['**/node_modules/**', '**/dist/**', '**/.git/**'],
|
|
1239
966
|
});
|
|
1240
|
-
const agents =
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
967
|
+
const agents = [];
|
|
968
|
+
for (const file of files) {
|
|
969
|
+
try {
|
|
970
|
+
const raw = fs.readFileSync(file, 'utf8');
|
|
971
|
+
const doc = yaml.load(raw);
|
|
972
|
+
const meta = doc.metadata;
|
|
973
|
+
agents.push({
|
|
974
|
+
name: meta?.name || path.basename(path.dirname(file)),
|
|
975
|
+
version: meta?.version || 'unknown',
|
|
976
|
+
path: file,
|
|
977
|
+
kind: doc.kind || 'Agent',
|
|
978
|
+
apiVersion: doc.apiVersion || 'unknown',
|
|
979
|
+
description: meta?.description || '',
|
|
980
|
+
});
|
|
981
|
+
}
|
|
982
|
+
catch {
|
|
983
|
+
agents.push({ name: path.basename(file), path: file, error: 'Failed to parse' });
|
|
984
|
+
}
|
|
985
|
+
}
|
|
1250
986
|
if (input.format === 'json') {
|
|
1251
987
|
return okResponse({ count: agents.length, agents });
|
|
1252
988
|
}
|
|
1253
989
|
if (input.format === 'detailed') {
|
|
1254
|
-
const patterns = input.recursive
|
|
1255
|
-
? ['**/*.ossa.yaml', '**/*.ossa.yml', '**/.agents/*/manifest.ossa.yaml']
|
|
1256
|
-
: ['*.ossa.yaml', '*.ossa.yml', '.agents/*/manifest.ossa.yaml'];
|
|
1257
990
|
return okResponse({
|
|
1258
991
|
count: agents.length,
|
|
1259
992
|
agents,
|
|
@@ -1304,21 +1037,12 @@ async function handleInspect(args) {
|
|
|
1304
1037
|
name: meta?.name,
|
|
1305
1038
|
version: versionStr,
|
|
1306
1039
|
version_analysis: parsed
|
|
1307
|
-
? {
|
|
1308
|
-
major: parsed.major,
|
|
1309
|
-
minor: parsed.minor,
|
|
1310
|
-
patch: parsed.patch,
|
|
1311
|
-
prerelease: parsed.prerelease,
|
|
1312
|
-
}
|
|
1040
|
+
? { major: parsed.major, minor: parsed.minor, patch: parsed.patch, prerelease: parsed.prerelease }
|
|
1313
1041
|
: null,
|
|
1314
1042
|
kind: manifest.kind,
|
|
1315
1043
|
apiVersion: manifest.apiVersion,
|
|
1316
|
-
mesh_bindings: meta?.mesh_bindings || null,
|
|
1317
1044
|
description: meta?.description,
|
|
1318
|
-
role: spec?.role
|
|
1319
|
-
? String(spec.role).substring(0, 200) +
|
|
1320
|
-
(String(spec.role).length > 200 ? '...' : '')
|
|
1321
|
-
: null,
|
|
1045
|
+
role: spec?.role ? String(spec.role).substring(0, 200) + (String(spec.role).length > 200 ? '...' : '') : null,
|
|
1322
1046
|
llm: spec?.llm || null,
|
|
1323
1047
|
tools: toolSummary,
|
|
1324
1048
|
tool_count: specTools.length,
|
|
@@ -1339,524 +1063,552 @@ async function handleInspect(args) {
|
|
|
1339
1063
|
// ---------------------------------------------------------------------------
|
|
1340
1064
|
// ossa_convert — export to target platform format
|
|
1341
1065
|
//
|
|
1342
|
-
//
|
|
1343
|
-
//
|
|
1344
|
-
//
|
|
1066
|
+
// HACK: These inline adapters produce lightweight JSON configs suitable for
|
|
1067
|
+
// MCP tool responses. The CLI export adapters (src/adapters/) generate full
|
|
1068
|
+
// multi-file project scaffolds (Dockerfile, docker-compose, Python packages,
|
|
1069
|
+
// etc.) which are too heavy for MCP responses. This is intentional divergence.
|
|
1070
|
+
// TODO(#442): Create a shared "config-only" export mode in the adapter classes
|
|
1071
|
+
// so both CLI and MCP can use the same code path.
|
|
1345
1072
|
// ---------------------------------------------------------------------------
|
|
1346
1073
|
async function handleConvert(args) {
|
|
1347
1074
|
const input = ConvertInput.parse(args);
|
|
1348
1075
|
const manifestPath = resolvePath(input.path);
|
|
1349
1076
|
const manifest = await manifestRepo.load(manifestPath);
|
|
1350
|
-
const meta = manifest.metadata || {
|
|
1351
|
-
name: path.basename(manifestPath, '.ossa.yaml'),
|
|
1352
|
-
version: '0.0.0',
|
|
1353
|
-
};
|
|
1077
|
+
const meta = manifest.metadata || { name: path.basename(manifestPath, '.ossa.yaml'), version: '0.0.0' };
|
|
1354
1078
|
let converted;
|
|
1355
1079
|
let filename;
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1080
|
+
switch (input.target) {
|
|
1081
|
+
case 'kagent': {
|
|
1082
|
+
// Generate kagent.dev v1alpha2 format (actual CRD that kagent controller understands)
|
|
1083
|
+
const kagentExtensions = manifest.extensions;
|
|
1084
|
+
const kagentExt = kagentExtensions?.kagent;
|
|
1085
|
+
const kagentNs = kagentExt?.kubernetes?.namespace || 'kagent';
|
|
1086
|
+
const a2aConfig = kagentExt?.a2aConfig;
|
|
1087
|
+
// Map OSSA tools to kagent McpServer tool format
|
|
1088
|
+
const ossaTools = (manifest.spec?.tools || []);
|
|
1089
|
+
const kagentTools = ossaTools.map((t) => {
|
|
1090
|
+
if (t.type === 'mcp') {
|
|
1091
|
+
return {
|
|
1092
|
+
type: 'McpServer',
|
|
1093
|
+
mcpServer: {
|
|
1094
|
+
name: t.server || t.name || 'tool-server',
|
|
1095
|
+
kind: 'RemoteMCPServer',
|
|
1096
|
+
...(t.toolNames ? { toolNames: t.toolNames } : {}),
|
|
1097
|
+
},
|
|
1098
|
+
};
|
|
1099
|
+
}
|
|
1100
|
+
return {
|
|
1101
|
+
type: 'McpServer',
|
|
1102
|
+
mcpServer: {
|
|
1103
|
+
name: t.name || 'tool-server',
|
|
1104
|
+
kind: 'RemoteMCPServer',
|
|
1105
|
+
},
|
|
1106
|
+
};
|
|
1107
|
+
});
|
|
1108
|
+
// Build the v1alpha2 Agent CRD
|
|
1109
|
+
converted = {
|
|
1110
|
+
apiVersion: 'kagent.dev/v1alpha2',
|
|
1111
|
+
kind: 'Agent',
|
|
1112
|
+
metadata: {
|
|
1113
|
+
name: meta.name,
|
|
1114
|
+
namespace: kagentNs,
|
|
1115
|
+
labels: {
|
|
1116
|
+
'ossa.dev/name': meta.name,
|
|
1117
|
+
'ossa.dev/version': meta.version || '0.0.0',
|
|
1118
|
+
'app.kubernetes.io/managed-by': 'ossa',
|
|
1119
|
+
},
|
|
1120
|
+
},
|
|
1121
|
+
spec: {
|
|
1122
|
+
description: meta.description || '',
|
|
1123
|
+
type: 'Declarative',
|
|
1124
|
+
declarative: {
|
|
1125
|
+
modelConfig: `${meta.name}-model-config`,
|
|
1126
|
+
systemMessage: manifest.spec?.role || '',
|
|
1127
|
+
tools: kagentTools,
|
|
1128
|
+
...(a2aConfig ? { a2aConfig } : {}),
|
|
1129
|
+
},
|
|
1130
|
+
},
|
|
1131
|
+
};
|
|
1132
|
+
// Also generate the ModelConfig companion resource
|
|
1133
|
+
const modelConfig = {
|
|
1134
|
+
apiVersion: 'kagent.dev/v1alpha2',
|
|
1135
|
+
kind: 'ModelConfig',
|
|
1136
|
+
metadata: {
|
|
1137
|
+
name: `${meta.name}-model-config`,
|
|
1138
|
+
namespace: kagentNs,
|
|
1139
|
+
},
|
|
1140
|
+
spec: {
|
|
1141
|
+
provider: manifest.spec?.llm?.provider || 'openai',
|
|
1142
|
+
model: manifest.spec?.llm?.model || 'gpt-4',
|
|
1143
|
+
...(manifest.spec?.llm?.temperature != null ? { temperature: manifest.spec.llm.temperature } : {}),
|
|
1144
|
+
...(manifest.spec?.llm?.maxTokens != null ? { maxTokens: manifest.spec.llm.maxTokens } : {}),
|
|
1145
|
+
},
|
|
1146
|
+
};
|
|
1147
|
+
// Return both resources in a multi-document YAML
|
|
1148
|
+
converted = {
|
|
1149
|
+
_ossa_multi_resource: true,
|
|
1150
|
+
resources: [converted, modelConfig],
|
|
1151
|
+
agent: converted,
|
|
1152
|
+
modelConfig,
|
|
1153
|
+
};
|
|
1154
|
+
filename = `${meta.name}.kagent.yaml`;
|
|
1155
|
+
break;
|
|
1366
1156
|
}
|
|
1367
|
-
|
|
1368
|
-
|
|
1157
|
+
case 'docker': {
|
|
1158
|
+
converted = {
|
|
1159
|
+
version: '3.8',
|
|
1160
|
+
services: {
|
|
1161
|
+
[meta.name]: {
|
|
1162
|
+
image: `ossa/${meta.name}:${meta.version || 'latest'}`,
|
|
1163
|
+
environment: {
|
|
1164
|
+
AGENT_NAME: meta.name,
|
|
1165
|
+
LLM_PROVIDER: manifest.spec?.llm?.provider || 'openai',
|
|
1166
|
+
LLM_MODEL: manifest.spec?.llm?.model || 'gpt-4',
|
|
1167
|
+
},
|
|
1168
|
+
labels: {
|
|
1169
|
+
'ossa.name': meta.name,
|
|
1170
|
+
'ossa.version': meta.version || '0.0.0',
|
|
1171
|
+
'ossa.kind': manifest.kind || 'Agent',
|
|
1172
|
+
},
|
|
1173
|
+
},
|
|
1174
|
+
},
|
|
1175
|
+
};
|
|
1176
|
+
filename = `docker-compose.${meta.name}.yml`;
|
|
1177
|
+
break;
|
|
1369
1178
|
}
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
id: t.name,
|
|
1392
|
-
name: t.name,
|
|
1393
|
-
description: t.description,
|
|
1394
|
-
...(t.inputSchema ? { inputModes: ['application/json'] } : {}),
|
|
1395
|
-
outputModes: ['application/json', 'text/plain'],
|
|
1396
|
-
}));
|
|
1397
|
-
// MCP tool format (Model Context Protocol)
|
|
1398
|
-
const mcpTools = universalTools.map((t) => ({
|
|
1399
|
-
name: t.name,
|
|
1400
|
-
description: t.description,
|
|
1401
|
-
inputSchema: t.inputSchema,
|
|
1402
|
-
}));
|
|
1403
|
-
// OpenAI function_calling format
|
|
1404
|
-
const openaiTools = universalTools.map((t) => ({
|
|
1405
|
-
type: 'function',
|
|
1406
|
-
function: {
|
|
1407
|
-
name: t.name,
|
|
1408
|
-
description: t.description,
|
|
1409
|
-
parameters: t.inputSchema,
|
|
1410
|
-
},
|
|
1411
|
-
}));
|
|
1412
|
-
// Anthropic tool_use format
|
|
1413
|
-
const anthropicTools = universalTools.map((t) => ({
|
|
1414
|
-
name: t.name,
|
|
1415
|
-
description: t.description,
|
|
1416
|
-
input_schema: t.inputSchema,
|
|
1417
|
-
}));
|
|
1418
|
-
// LangChain StructuredTool format
|
|
1419
|
-
const langchainTools = universalTools.map((t) => ({
|
|
1420
|
-
_type: 'structured_tool',
|
|
1421
|
-
name: t.name,
|
|
1422
|
-
description: t.description,
|
|
1423
|
-
args_schema: t.inputSchema,
|
|
1424
|
-
}));
|
|
1425
|
-
// CrewAI tool format
|
|
1426
|
-
const crewaiTools = universalTools.map((t) => ({
|
|
1427
|
-
name: t.name,
|
|
1428
|
-
description: t.description,
|
|
1429
|
-
...(t.inputSchema ? { args_schema: t.inputSchema } : {}),
|
|
1430
|
-
}));
|
|
1431
|
-
// LangFlow component format
|
|
1432
|
-
const langflowComponent = {
|
|
1433
|
-
display_name: meta.name,
|
|
1434
|
-
description,
|
|
1435
|
-
documentation: `https://openstandardagents.org/agents/${meta.name}`,
|
|
1436
|
-
template: {
|
|
1437
|
-
system_message: { type: 'str', value: role },
|
|
1438
|
-
model_name: { type: 'str', value: model },
|
|
1439
|
-
provider: { type: 'str', value: provider },
|
|
1440
|
-
tools: { type: 'list', value: universalTools.map((t) => t.name) },
|
|
1441
|
-
},
|
|
1442
|
-
};
|
|
1443
|
-
// AutoGen agent format
|
|
1444
|
-
const autogenConfig = {
|
|
1445
|
-
name: meta.name,
|
|
1446
|
-
description,
|
|
1447
|
-
system_message: role,
|
|
1448
|
-
llm_config: {
|
|
1449
|
-
config_list: [
|
|
1179
|
+
case 'langchain': {
|
|
1180
|
+
converted = {
|
|
1181
|
+
_type: 'agent',
|
|
1182
|
+
name: meta.name,
|
|
1183
|
+
description: meta.description || '',
|
|
1184
|
+
llm: {
|
|
1185
|
+
_type: manifest.spec?.llm?.provider === 'anthropic' ? 'ChatAnthropic' : 'ChatOpenAI',
|
|
1186
|
+
model_name: manifest.spec?.llm?.model || 'gpt-4',
|
|
1187
|
+
},
|
|
1188
|
+
system_message: manifest.spec?.role || '',
|
|
1189
|
+
tools: (manifest.spec?.tools || []).map((t) => ({
|
|
1190
|
+
name: t.name,
|
|
1191
|
+
type: t.type,
|
|
1192
|
+
})),
|
|
1193
|
+
};
|
|
1194
|
+
filename = `${meta.name}.langchain.json`;
|
|
1195
|
+
break;
|
|
1196
|
+
}
|
|
1197
|
+
case 'crewai': {
|
|
1198
|
+
converted = {
|
|
1199
|
+
agents: [
|
|
1450
1200
|
{
|
|
1451
|
-
|
|
1452
|
-
|
|
1201
|
+
role: meta.name,
|
|
1202
|
+
goal: meta.description || '',
|
|
1203
|
+
backstory: manifest.spec?.role || '',
|
|
1204
|
+
llm: manifest.spec?.llm?.model || 'gpt-4',
|
|
1205
|
+
tools: (manifest.spec?.tools || []).map((t) => t.name),
|
|
1453
1206
|
},
|
|
1454
1207
|
],
|
|
1455
|
-
}
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
:
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1208
|
+
};
|
|
1209
|
+
filename = `${meta.name}.crewai.yaml`;
|
|
1210
|
+
break;
|
|
1211
|
+
}
|
|
1212
|
+
case 'gitlab-duo': {
|
|
1213
|
+
converted = {
|
|
1214
|
+
name: meta.name,
|
|
1215
|
+
description: meta.description || '',
|
|
1216
|
+
system_prompt: manifest.spec?.role || '',
|
|
1217
|
+
model: manifest.spec?.llm?.model || 'claude-sonnet-4-20250514',
|
|
1218
|
+
tools: (manifest.spec?.tools || []).map((t) => ({
|
|
1219
|
+
name: t.name,
|
|
1220
|
+
})),
|
|
1221
|
+
};
|
|
1222
|
+
filename = `${meta.name}.duo-agent.yaml`;
|
|
1223
|
+
break;
|
|
1224
|
+
}
|
|
1225
|
+
case 'anthropic': {
|
|
1226
|
+
converted = {
|
|
1227
|
+
name: meta.name,
|
|
1228
|
+
description: meta.description || '',
|
|
1229
|
+
model: manifest.spec?.llm?.model || 'claude-sonnet-4-20250514',
|
|
1230
|
+
system: manifest.spec?.role || '',
|
|
1231
|
+
tools: (manifest.spec?.tools || []).map((t) => ({
|
|
1232
|
+
name: t.name,
|
|
1233
|
+
description: '',
|
|
1234
|
+
input_schema: { type: 'object', properties: {} },
|
|
1235
|
+
})),
|
|
1236
|
+
max_tokens: 4096,
|
|
1237
|
+
};
|
|
1238
|
+
filename = `${meta.name}.anthropic.json`;
|
|
1239
|
+
break;
|
|
1240
|
+
}
|
|
1241
|
+
case 'openai': {
|
|
1242
|
+
// OpenAI Assistants / function_calling format
|
|
1243
|
+
const oaiTools = (manifest.spec?.tools || []);
|
|
1244
|
+
converted = {
|
|
1245
|
+
model: manifest.spec?.llm?.model || 'gpt-4',
|
|
1246
|
+
name: meta.name,
|
|
1247
|
+
description: meta.description || '',
|
|
1248
|
+
instructions: manifest.spec?.role || '',
|
|
1249
|
+
tools: oaiTools.map((t) => ({
|
|
1250
|
+
type: 'function',
|
|
1251
|
+
function: {
|
|
1252
|
+
name: t.name || 'unnamed',
|
|
1253
|
+
description: t.description || '',
|
|
1254
|
+
parameters: t.inputSchema || t.input_schema || t.parameters || { type: 'object', properties: {} },
|
|
1255
|
+
},
|
|
1256
|
+
})),
|
|
1257
|
+
metadata: {
|
|
1258
|
+
ossa_version: manifest.apiVersion || 'ossa/v0.4',
|
|
1259
|
+
ossa_name: meta.name,
|
|
1487
1260
|
},
|
|
1488
|
-
}
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1261
|
+
};
|
|
1262
|
+
filename = `${meta.name}.openai.json`;
|
|
1263
|
+
break;
|
|
1264
|
+
}
|
|
1265
|
+
case 'autogen': {
|
|
1266
|
+
// Microsoft AutoGen agent config
|
|
1267
|
+
const autogenTools = (manifest.spec?.tools || []);
|
|
1268
|
+
converted = {
|
|
1269
|
+
name: meta.name,
|
|
1270
|
+
description: meta.description || '',
|
|
1271
|
+
system_message: manifest.spec?.role || '',
|
|
1272
|
+
llm_config: {
|
|
1273
|
+
config_list: [
|
|
1274
|
+
{
|
|
1275
|
+
model: manifest.spec?.llm?.model || 'gpt-4',
|
|
1276
|
+
api_type: manifest.spec?.llm?.provider === 'anthropic' ? 'anthropic' : 'openai',
|
|
1277
|
+
},
|
|
1278
|
+
],
|
|
1279
|
+
...(manifest.spec?.llm?.temperature != null ? { temperature: manifest.spec.llm.temperature } : {}),
|
|
1280
|
+
...(manifest.spec?.llm?.maxTokens != null ? { max_tokens: manifest.spec.llm.maxTokens } : {}),
|
|
1281
|
+
},
|
|
1282
|
+
...(autogenTools.length > 0
|
|
1283
|
+
? {
|
|
1284
|
+
tools: autogenTools.map((t) => ({
|
|
1285
|
+
name: t.name || 'unnamed',
|
|
1286
|
+
description: t.description || '',
|
|
1287
|
+
...(t.inputSchema || t.input_schema ? { parameters: t.inputSchema || t.input_schema } : {}),
|
|
1288
|
+
})),
|
|
1289
|
+
}
|
|
1516
1290
|
: {}),
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
capabilities: {
|
|
1520
|
-
streaming: true,
|
|
1521
|
-
pushNotifications: false,
|
|
1522
|
-
stateTransitionHistory: true,
|
|
1523
|
-
},
|
|
1524
|
-
skills: a2aSkills,
|
|
1525
|
-
defaultInputModes: ['application/json', 'text/plain'],
|
|
1526
|
-
defaultOutputModes: ['application/json', 'text/plain'],
|
|
1527
|
-
// --- MCP tools (Model Context Protocol) ---
|
|
1528
|
-
mcp: {
|
|
1529
|
-
tools: mcpTools,
|
|
1530
|
-
...(mcpExt?.servers ? { servers: mcpExt.servers } : {}),
|
|
1531
|
-
...(mcpExt?.resources ? { resources: mcpExt.resources } : {}),
|
|
1532
|
-
},
|
|
1533
|
-
// --- Platform adapters (use these directly in your framework) ---
|
|
1534
|
-
// Each adapter includes: sdk (npm/pip packages), config (ready-to-use), usage (code snippet)
|
|
1535
|
-
adapters: {
|
|
1536
|
-
openai: {
|
|
1537
|
-
sdk: {
|
|
1538
|
-
npm: 'openai',
|
|
1539
|
-
pip: 'openai',
|
|
1540
|
-
docs: 'https://platform.openai.com/docs/api-reference',
|
|
1541
|
-
},
|
|
1542
|
-
config: {
|
|
1543
|
-
model,
|
|
1544
|
-
messages: [{ role: 'system', content: role }],
|
|
1545
|
-
tools: openaiTools,
|
|
1546
|
-
tool_choice: 'auto',
|
|
1547
|
-
},
|
|
1548
|
-
usage: `import OpenAI from 'openai';\nconst client = new OpenAI();\nconst response = await client.chat.completions.create(config);`,
|
|
1291
|
+
metadata: {
|
|
1292
|
+
ossa_version: manifest.apiVersion || 'ossa/v0.4',
|
|
1549
1293
|
},
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1294
|
+
};
|
|
1295
|
+
filename = `${meta.name}.autogen.json`;
|
|
1296
|
+
break;
|
|
1297
|
+
}
|
|
1298
|
+
case 'semantic-kernel': {
|
|
1299
|
+
// Microsoft Semantic Kernel agent config
|
|
1300
|
+
const skTools = (manifest.spec?.tools || []);
|
|
1301
|
+
converted = {
|
|
1302
|
+
name: meta.name,
|
|
1303
|
+
description: meta.description || '',
|
|
1304
|
+
instructions: manifest.spec?.role || '',
|
|
1305
|
+
execution_settings: {
|
|
1306
|
+
default: {
|
|
1307
|
+
model_id: manifest.spec?.llm?.model || 'gpt-4',
|
|
1308
|
+
service_id: manifest.spec?.llm?.provider || 'openai',
|
|
1309
|
+
...(manifest.spec?.llm?.temperature != null ? { temperature: manifest.spec.llm.temperature } : {}),
|
|
1310
|
+
...(manifest.spec?.llm?.maxTokens != null ? { max_tokens: manifest.spec.llm.maxTokens } : {}),
|
|
1561
1311
|
},
|
|
1562
|
-
usage: `import Anthropic from '@anthropic-ai/sdk';\nconst client = new Anthropic();\nconst response = await client.messages.create(config);`,
|
|
1563
1312
|
},
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1313
|
+
plugins: skTools.map((t) => ({
|
|
1314
|
+
name: t.name || 'unnamed',
|
|
1315
|
+
description: t.description || '',
|
|
1316
|
+
parameters: t.inputSchema || t.input_schema || t.parameters || { type: 'object', properties: {} },
|
|
1317
|
+
})),
|
|
1318
|
+
metadata: {
|
|
1319
|
+
ossa_version: manifest.apiVersion || 'ossa/v0.4',
|
|
1320
|
+
},
|
|
1321
|
+
};
|
|
1322
|
+
filename = `${meta.name}.semantic-kernel.json`;
|
|
1323
|
+
break;
|
|
1324
|
+
}
|
|
1325
|
+
case 'a2a':
|
|
1326
|
+
case 'agent-card': {
|
|
1327
|
+
// Build comprehensive cross-platform agent card
|
|
1328
|
+
// This is THE universal discovery format: MCP → OSSA → A2A
|
|
1329
|
+
let cardResult = { success: false, errors: [] };
|
|
1330
|
+
try {
|
|
1331
|
+
cardResult = agentCardGenerator.generate(manifest);
|
|
1332
|
+
}
|
|
1333
|
+
catch {
|
|
1334
|
+
// AgentCardGenerator may fail on some manifests — continue building the card
|
|
1335
|
+
}
|
|
1336
|
+
const tools = (manifest.spec?.tools || []);
|
|
1337
|
+
const role = manifest.spec?.role || '';
|
|
1338
|
+
const llm = manifest.spec?.llm;
|
|
1339
|
+
const provider = llm?.provider || 'openai';
|
|
1340
|
+
const model = llm?.model || 'gpt-4';
|
|
1341
|
+
const description = meta.description || '';
|
|
1342
|
+
// Build universal tool schemas for cross-platform use
|
|
1343
|
+
const universalTools = tools.map((t) => ({
|
|
1344
|
+
name: t.name || 'unnamed',
|
|
1345
|
+
description: t.description || '',
|
|
1346
|
+
inputSchema: (t.inputSchema || t.input_schema || t.parameters || { type: 'object', properties: {} }),
|
|
1347
|
+
...(t.outputSchema || t.output_schema ? { outputSchema: t.outputSchema || t.output_schema } : {}),
|
|
1348
|
+
...(t.type ? { type: t.type } : {}),
|
|
1349
|
+
...(t.server ? { mcpServer: t.server } : {}),
|
|
1350
|
+
}));
|
|
1351
|
+
// A2A skills from tools (Google A2A agent card format)
|
|
1352
|
+
const a2aSkills = universalTools.map((t) => ({
|
|
1353
|
+
id: t.name,
|
|
1354
|
+
name: t.name,
|
|
1355
|
+
description: t.description,
|
|
1356
|
+
...(t.inputSchema ? { inputModes: ['application/json'] } : {}),
|
|
1357
|
+
outputModes: ['application/json', 'text/plain'],
|
|
1358
|
+
}));
|
|
1359
|
+
// MCP tool format (Model Context Protocol)
|
|
1360
|
+
const mcpTools = universalTools.map((t) => ({
|
|
1361
|
+
name: t.name,
|
|
1362
|
+
description: t.description,
|
|
1363
|
+
inputSchema: t.inputSchema,
|
|
1364
|
+
}));
|
|
1365
|
+
// OpenAI function_calling format
|
|
1366
|
+
const openaiTools = universalTools.map((t) => ({
|
|
1367
|
+
type: 'function',
|
|
1368
|
+
function: {
|
|
1369
|
+
name: t.name,
|
|
1370
|
+
description: t.description,
|
|
1371
|
+
parameters: t.inputSchema,
|
|
1372
|
+
},
|
|
1373
|
+
}));
|
|
1374
|
+
// Anthropic tool_use format
|
|
1375
|
+
const anthropicTools = universalTools.map((t) => ({
|
|
1376
|
+
name: t.name,
|
|
1377
|
+
description: t.description,
|
|
1378
|
+
input_schema: t.inputSchema,
|
|
1379
|
+
}));
|
|
1380
|
+
// LangChain StructuredTool format
|
|
1381
|
+
const langchainTools = universalTools.map((t) => ({
|
|
1382
|
+
_type: 'structured_tool',
|
|
1383
|
+
name: t.name,
|
|
1384
|
+
description: t.description,
|
|
1385
|
+
args_schema: t.inputSchema,
|
|
1386
|
+
}));
|
|
1387
|
+
// CrewAI tool format
|
|
1388
|
+
const crewaiTools = universalTools.map((t) => ({
|
|
1389
|
+
name: t.name,
|
|
1390
|
+
description: t.description,
|
|
1391
|
+
...(t.inputSchema ? { args_schema: t.inputSchema } : {}),
|
|
1392
|
+
}));
|
|
1393
|
+
// LangFlow component format
|
|
1394
|
+
const langflowComponent = {
|
|
1395
|
+
display_name: meta.name,
|
|
1396
|
+
description,
|
|
1397
|
+
documentation: `https://openstandardagents.org/agents/${meta.name}`,
|
|
1398
|
+
template: {
|
|
1399
|
+
system_message: { type: 'str', value: role },
|
|
1400
|
+
model_name: { type: 'str', value: model },
|
|
1401
|
+
provider: { type: 'str', value: provider },
|
|
1402
|
+
tools: { type: 'list', value: universalTools.map((t) => t.name) },
|
|
1403
|
+
},
|
|
1404
|
+
};
|
|
1405
|
+
// AutoGen agent format
|
|
1406
|
+
const autogenConfig = {
|
|
1407
|
+
name: meta.name,
|
|
1408
|
+
description,
|
|
1409
|
+
system_message: role,
|
|
1410
|
+
llm_config: {
|
|
1411
|
+
config_list: [{ model, api_type: provider === 'anthropic' ? 'anthropic' : 'openai' }],
|
|
1412
|
+
},
|
|
1413
|
+
...(universalTools.length > 0 ? { tools: universalTools.map((t) => ({ name: t.name, description: t.description })) } : {}),
|
|
1414
|
+
};
|
|
1415
|
+
// Semantic Kernel agent format
|
|
1416
|
+
const semanticKernelConfig = {
|
|
1417
|
+
name: meta.name,
|
|
1418
|
+
description,
|
|
1419
|
+
instructions: role,
|
|
1420
|
+
model: { id: model, provider },
|
|
1421
|
+
plugins: universalTools.map((t) => ({
|
|
1422
|
+
name: t.name,
|
|
1423
|
+
description: t.description,
|
|
1424
|
+
parameters: t.inputSchema,
|
|
1425
|
+
})),
|
|
1426
|
+
};
|
|
1427
|
+
// kagent.dev CRD reference (not full CRD — use target: kagent for that)
|
|
1428
|
+
const kagentRef = {
|
|
1429
|
+
apiVersion: 'kagent.dev/v1alpha2',
|
|
1430
|
+
kind: 'Agent',
|
|
1431
|
+
metadata: { name: meta.name },
|
|
1432
|
+
spec: {
|
|
1433
|
+
type: 'Declarative',
|
|
1434
|
+
declarative: {
|
|
1435
|
+
modelConfig: `${meta.name}-model-config`,
|
|
1436
|
+
systemMessage: role,
|
|
1576
1437
|
},
|
|
1577
|
-
usage: `import { GoogleGenerativeAI } from '@google/generative-ai';\nconst genAI = new GoogleGenerativeAI(apiKey);\nconst model = genAI.getGenerativeModel(config);`,
|
|
1578
1438
|
},
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1439
|
+
};
|
|
1440
|
+
// Extensions from OSSA manifest
|
|
1441
|
+
const extensions = manifest.extensions;
|
|
1442
|
+
const a2aExt = extensions?.a2a;
|
|
1443
|
+
const mcpExt = extensions?.mcp;
|
|
1444
|
+
// Build the comprehensive agent card
|
|
1445
|
+
converted = {
|
|
1446
|
+
// --- Core identity (OSSA source of truth) ---
|
|
1447
|
+
name: meta.name,
|
|
1448
|
+
version: meta.version || '1.0.0',
|
|
1449
|
+
description,
|
|
1450
|
+
url: `https://openstandardagents.org/agents/${meta.name}`,
|
|
1451
|
+
ossaVersion: manifest.apiVersion || 'ossa/v0.4',
|
|
1452
|
+
kind: manifest.kind || 'Agent',
|
|
1453
|
+
// --- The OSSA contract (identity + capabilities + constraints) ---
|
|
1454
|
+
ossa: {
|
|
1455
|
+
role,
|
|
1456
|
+
capabilities: (manifest.spec?.capabilities || []),
|
|
1457
|
+
...(manifest.spec?.autonomy ? { autonomy: manifest.spec.autonomy } : {}),
|
|
1458
|
+
...(manifest.spec?.safety ? { safety: manifest.spec.safety } : {}),
|
|
1459
|
+
...(manifest.spec?.observability ? { observability: manifest.spec.observability } : {}),
|
|
1460
|
+
...(manifest.spec?.access ? { access: manifest.spec.access } : {}),
|
|
1461
|
+
},
|
|
1462
|
+
// --- A2A discovery (Google Agent-to-Agent protocol) ---
|
|
1463
|
+
capabilities: {
|
|
1464
|
+
streaming: true,
|
|
1465
|
+
pushNotifications: false,
|
|
1466
|
+
stateTransitionHistory: true,
|
|
1467
|
+
},
|
|
1468
|
+
skills: a2aSkills,
|
|
1469
|
+
defaultInputModes: ['application/json', 'text/plain'],
|
|
1470
|
+
defaultOutputModes: ['application/json', 'text/plain'],
|
|
1471
|
+
// --- MCP tools (Model Context Protocol) ---
|
|
1472
|
+
mcp: {
|
|
1473
|
+
tools: mcpTools,
|
|
1474
|
+
...(mcpExt?.servers ? { servers: mcpExt.servers } : {}),
|
|
1475
|
+
...(mcpExt?.resources ? { resources: mcpExt.resources } : {}),
|
|
1476
|
+
},
|
|
1477
|
+
// --- Platform adapters (use these directly in your framework) ---
|
|
1478
|
+
// Each adapter includes: sdk (npm/pip packages), config (ready-to-use), usage (code snippet)
|
|
1479
|
+
adapters: {
|
|
1480
|
+
openai: {
|
|
1481
|
+
sdk: { npm: 'openai', pip: 'openai', docs: 'https://platform.openai.com/docs/api-reference' },
|
|
1482
|
+
config: {
|
|
1483
|
+
model,
|
|
1484
|
+
messages: [{ role: 'system', content: role }],
|
|
1485
|
+
tools: openaiTools,
|
|
1486
|
+
tool_choice: 'auto',
|
|
1487
|
+
},
|
|
1488
|
+
usage: `import OpenAI from 'openai';\nconst client = new OpenAI();\nconst response = await client.chat.completions.create(config);`,
|
|
1589
1489
|
},
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1490
|
+
anthropic: {
|
|
1491
|
+
sdk: { npm: '@anthropic-ai/sdk', pip: 'anthropic', docs: 'https://docs.anthropic.com/en/api' },
|
|
1492
|
+
config: {
|
|
1493
|
+
model: provider === 'anthropic' ? model : 'claude-sonnet-4-20250514',
|
|
1494
|
+
system: role,
|
|
1495
|
+
tools: anthropicTools,
|
|
1496
|
+
max_tokens: llm?.maxTokens || 4096,
|
|
1596
1497
|
},
|
|
1597
|
-
|
|
1598
|
-
tools: langchainTools,
|
|
1498
|
+
usage: `import Anthropic from '@anthropic-ai/sdk';\nconst client = new Anthropic();\nconst response = await client.messages.create(config);`,
|
|
1599
1499
|
},
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1500
|
+
google_genai: {
|
|
1501
|
+
sdk: { npm: '@google/generative-ai', pip: 'google-generativeai', docs: 'https://ai.google.dev/docs' },
|
|
1502
|
+
config: {
|
|
1503
|
+
model: 'gemini-2.0-flash',
|
|
1504
|
+
systemInstruction: role,
|
|
1505
|
+
tools: [{ functionDeclarations: openaiTools.map((t) => t.function) }],
|
|
1506
|
+
},
|
|
1507
|
+
usage: `import { GoogleGenerativeAI } from '@google/generative-ai';\nconst genAI = new GoogleGenerativeAI(apiKey);\nconst model = genAI.getGenerativeModel(config);`,
|
|
1508
|
+
},
|
|
1509
|
+
langchain: {
|
|
1510
|
+
sdk: {
|
|
1511
|
+
npm: ['langchain', '@langchain/core', '@langchain/openai', '@langchain/anthropic'],
|
|
1512
|
+
pip: ['langchain', 'langchain-openai', 'langchain-anthropic'],
|
|
1513
|
+
docs: 'https://js.langchain.com/docs/',
|
|
1514
|
+
},
|
|
1515
|
+
config: {
|
|
1516
|
+
_type: 'agent',
|
|
1517
|
+
name: meta.name,
|
|
1518
|
+
llm: {
|
|
1519
|
+
_type: provider === 'anthropic' ? 'ChatAnthropic' : 'ChatOpenAI',
|
|
1520
|
+
model_name: model,
|
|
1617
1521
|
},
|
|
1618
|
-
|
|
1522
|
+
system_message: role,
|
|
1523
|
+
tools: langchainTools,
|
|
1524
|
+
},
|
|
1525
|
+
usage: `from langchain.agents import create_tool_calling_agent\nagent = create_tool_calling_agent(llm, tools, prompt)`,
|
|
1619
1526
|
},
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
pip: 'autogen-agentchat',
|
|
1625
|
-
docs: 'https://microsoft.github.io/autogen/',
|
|
1527
|
+
langflow: {
|
|
1528
|
+
sdk: { pip: 'langflow', docs: 'https://docs.langflow.org/' },
|
|
1529
|
+
config: langflowComponent,
|
|
1530
|
+
usage: 'Import as custom component in LangFlow UI or use langflow CLI',
|
|
1626
1531
|
},
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1532
|
+
crewai: {
|
|
1533
|
+
sdk: { pip: 'crewai', docs: 'https://docs.crewai.com/' },
|
|
1534
|
+
config: {
|
|
1535
|
+
agents: [{
|
|
1536
|
+
role: meta.name,
|
|
1537
|
+
goal: description,
|
|
1538
|
+
backstory: role,
|
|
1539
|
+
llm: model,
|
|
1540
|
+
tools: crewaiTools,
|
|
1541
|
+
}],
|
|
1542
|
+
},
|
|
1543
|
+
usage: `from crewai import Agent\nagent = Agent(role=config['role'], goal=config['goal'], backstory=config['backstory'])`,
|
|
1635
1544
|
},
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
sdk: {
|
|
1641
|
-
npm: 'llamaindex',
|
|
1642
|
-
pip: 'llama-index',
|
|
1643
|
-
docs: 'https://docs.llamaindex.ai/',
|
|
1545
|
+
autogen: {
|
|
1546
|
+
sdk: { pip: 'autogen-agentchat', docs: 'https://microsoft.github.io/autogen/' },
|
|
1547
|
+
config: autogenConfig,
|
|
1548
|
+
usage: `from autogen import ConversableAgent\nagent = ConversableAgent(name=config['name'], system_message=config['system_message'], llm_config=config['llm_config'])`,
|
|
1644
1549
|
},
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
llm: { model, provider },
|
|
1650
|
-
tools: universalTools.map((t) => ({
|
|
1651
|
-
name: t.name,
|
|
1652
|
-
description: t.description,
|
|
1653
|
-
fn_schema: t.inputSchema,
|
|
1654
|
-
})),
|
|
1550
|
+
semantic_kernel: {
|
|
1551
|
+
sdk: { npm: 'semantic-kernel', pip: 'semantic-kernel', docs: 'https://learn.microsoft.com/en-us/semantic-kernel/' },
|
|
1552
|
+
config: semanticKernelConfig,
|
|
1553
|
+
usage: `import semantic_kernel as sk\nkernel = sk.Kernel()\nkernel.add_chat_service("default", OpenAIChatCompletion(config['execution_settings']['default']['model_id']))`,
|
|
1655
1554
|
},
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1555
|
+
llamaindex: {
|
|
1556
|
+
sdk: { npm: 'llamaindex', pip: 'llama-index', docs: 'https://docs.llamaindex.ai/' },
|
|
1557
|
+
config: {
|
|
1558
|
+
name: meta.name,
|
|
1559
|
+
description,
|
|
1560
|
+
system_prompt: role,
|
|
1561
|
+
llm: { model, provider },
|
|
1562
|
+
tools: universalTools.map((t) => ({ name: t.name, description: t.description, fn_schema: t.inputSchema })),
|
|
1563
|
+
},
|
|
1564
|
+
usage: `from llama_index.agent.openai import OpenAIAgent\nagent = OpenAIAgent.from_tools(tools, system_prompt=config['system_prompt'])`,
|
|
1665
1565
|
},
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
config: {
|
|
1676
|
-
name: meta.name,
|
|
1677
|
-
description,
|
|
1678
|
-
system_prompt: role,
|
|
1679
|
-
model: provider === 'anthropic' ? model : 'claude-sonnet-4-20250514',
|
|
1680
|
-
tools: universalTools.map((t) => ({ name: t.name })),
|
|
1566
|
+
dspy: {
|
|
1567
|
+
sdk: { pip: 'dspy', docs: 'https://dspy.ai/' },
|
|
1568
|
+
config: {
|
|
1569
|
+
name: meta.name,
|
|
1570
|
+
instructions: role,
|
|
1571
|
+
lm: `${provider}/${model}`,
|
|
1572
|
+
tools: universalTools.map((t) => t.name),
|
|
1573
|
+
},
|
|
1574
|
+
usage: `import dspy\nlm = dspy.LM('${provider}/${model}')\ndspy.configure(lm=lm)`,
|
|
1681
1575
|
},
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
npm: '@anthropic-ai/claude-agent-sdk',
|
|
1687
|
-
pip: 'claude-agent-sdk',
|
|
1688
|
-
go: 'github.com/M1n9X/claude-agent-sdk-go',
|
|
1689
|
-
rust: 'claude_agent',
|
|
1690
|
-
docs: 'https://docs.claude.com/en/api/agent-sdk/overview',
|
|
1576
|
+
kagent: {
|
|
1577
|
+
sdk: { docs: 'https://kagent.dev/docs' },
|
|
1578
|
+
config: kagentRef,
|
|
1579
|
+
usage: 'kubectl apply -f <converted>.kagent.yaml # Use target: kagent for full CRD output',
|
|
1691
1580
|
},
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1581
|
+
gitlab_duo: {
|
|
1582
|
+
sdk: { docs: 'https://docs.gitlab.com/ee/user/gitlab_duo/' },
|
|
1583
|
+
config: {
|
|
1584
|
+
name: meta.name,
|
|
1585
|
+
description,
|
|
1586
|
+
system_prompt: role,
|
|
1587
|
+
model: provider === 'anthropic' ? model : 'claude-sonnet-4-20250514',
|
|
1588
|
+
tools: universalTools.map((t) => ({ name: t.name })),
|
|
1589
|
+
},
|
|
1590
|
+
usage: 'Place in .gitlab/duo/agents/ directory',
|
|
1696
1591
|
},
|
|
1697
|
-
usage: `import { query } from '@anthropic-ai/claude-agent-sdk';\nconst conversation = query({ prompt, options: config });\nfor await (const msg of conversation) { /* handle */ }`,
|
|
1698
1592
|
},
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
...(a2aExt
|
|
1702
|
-
? {
|
|
1593
|
+
// --- A2A protocol details (if defined in OSSA extensions) ---
|
|
1594
|
+
...(a2aExt ? {
|
|
1703
1595
|
a2a: {
|
|
1704
1596
|
...(a2aExt.protocol ? { protocol: a2aExt.protocol } : {}),
|
|
1705
1597
|
...(a2aExt.endpoints ? { endpoints: a2aExt.endpoints } : {}),
|
|
1706
1598
|
...(a2aExt.routing ? { routing: a2aExt.routing } : {}),
|
|
1707
1599
|
...(a2aExt.delegation ? { delegation: a2aExt.delegation } : {}),
|
|
1708
1600
|
},
|
|
1709
|
-
}
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
...(cardResult.success && cardResult.card
|
|
1713
|
-
? {
|
|
1601
|
+
} : {}),
|
|
1602
|
+
// --- Full OSSA agent card (from generator) ---
|
|
1603
|
+
...(cardResult.success && cardResult.card ? {
|
|
1714
1604
|
_agentCard: cardResult.card,
|
|
1715
|
-
}
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
}
|
|
1720
|
-
else if (input.target === 'claude-agent-sdk') {
|
|
1721
|
-
// Generate Claude Agent SDK application config (TypeScript + Python)
|
|
1722
|
-
const sdkTools = (manifest.spec?.tools || []);
|
|
1723
|
-
const sdkLlm = manifest.spec?.llm;
|
|
1724
|
-
const sdkModel = (typeof sdkLlm === 'string' ? sdkLlm : sdkLlm?.model) ||
|
|
1725
|
-
'claude-sonnet-4-20250514';
|
|
1726
|
-
const sdkRole = manifest.spec?.role || '';
|
|
1727
|
-
const sdkCaps = (manifest.spec?.capabilities || []).map((c) => typeof c === 'string' ? c : c.name || '');
|
|
1728
|
-
// Map capabilities to Claude Agent SDK built-in tools
|
|
1729
|
-
const builtInTools = [];
|
|
1730
|
-
const capToolMap = {
|
|
1731
|
-
'web-search': ['WebSearch', 'WebFetch'],
|
|
1732
|
-
'file-access': ['Read', 'Write', 'Edit', 'Glob', 'Grep'],
|
|
1733
|
-
'file-read': ['Read', 'Glob', 'Grep'],
|
|
1734
|
-
'file-write': ['Read', 'Write', 'Edit'],
|
|
1735
|
-
'code-execution': ['Bash'],
|
|
1736
|
-
shell: ['Bash'],
|
|
1737
|
-
bash: ['Bash'],
|
|
1738
|
-
'code-analysis': ['Read', 'Glob', 'Grep'],
|
|
1739
|
-
explore: ['Read', 'Glob', 'Grep'],
|
|
1740
|
-
};
|
|
1741
|
-
for (const cap of sdkCaps) {
|
|
1742
|
-
const mapped = capToolMap[cap];
|
|
1743
|
-
if (mapped) {
|
|
1744
|
-
for (const t of mapped) {
|
|
1745
|
-
if (!builtInTools.includes(t))
|
|
1746
|
-
builtInTools.push(t);
|
|
1747
|
-
}
|
|
1748
|
-
}
|
|
1749
|
-
}
|
|
1750
|
-
// Map MCP servers from tools
|
|
1751
|
-
const mcpServers = {};
|
|
1752
|
-
const customTools = [];
|
|
1753
|
-
for (const tool of sdkTools) {
|
|
1754
|
-
if (tool.type === 'mcp' && tool.server) {
|
|
1755
|
-
const sname = String(tool.server);
|
|
1756
|
-
if (!mcpServers[sname]) {
|
|
1757
|
-
mcpServers[sname] = {
|
|
1758
|
-
type: tool.transport || 'stdio',
|
|
1759
|
-
...(tool.command ? { command: tool.command } : {}),
|
|
1760
|
-
...(tool.args ? { args: tool.args } : {}),
|
|
1761
|
-
...(tool.url ? { url: tool.url } : {}),
|
|
1762
|
-
};
|
|
1763
|
-
}
|
|
1764
|
-
}
|
|
1765
|
-
else {
|
|
1766
|
-
customTools.push({
|
|
1767
|
-
name: tool.name || 'unnamed',
|
|
1768
|
-
description: tool.description || '',
|
|
1769
|
-
inputSchema: tool.inputSchema ||
|
|
1770
|
-
tool.input_schema ||
|
|
1771
|
-
tool.parameters || { type: 'object', properties: {} },
|
|
1772
|
-
});
|
|
1773
|
-
}
|
|
1774
|
-
}
|
|
1775
|
-
// Map autonomy to permission mode
|
|
1776
|
-
const sdkAutonomy = manifest.spec?.autonomy;
|
|
1777
|
-
let permissionMode = 'default';
|
|
1778
|
-
if (sdkAutonomy) {
|
|
1779
|
-
const level = sdkAutonomy.level || '';
|
|
1780
|
-
if (level === 'full' || level === 'autonomous')
|
|
1781
|
-
permissionMode = 'bypassPermissions';
|
|
1782
|
-
else if (level === 'supervised')
|
|
1783
|
-
permissionMode = 'acceptEdits';
|
|
1784
|
-
else if (level === 'planning')
|
|
1785
|
-
permissionMode = 'planMode';
|
|
1605
|
+
} : {}),
|
|
1606
|
+
};
|
|
1607
|
+
filename = 'agent-card.json';
|
|
1608
|
+
break;
|
|
1786
1609
|
}
|
|
1787
|
-
|
|
1788
|
-
let claudeModel = 'claude-sonnet-4-20250514';
|
|
1789
|
-
if (sdkModel.includes('opus'))
|
|
1790
|
-
claudeModel = 'claude-opus-4-20250514';
|
|
1791
|
-
else if (sdkModel.includes('haiku'))
|
|
1792
|
-
claudeModel = 'claude-haiku-4-5-20251001';
|
|
1793
|
-
else if (sdkModel.includes('sonnet'))
|
|
1794
|
-
claudeModel = 'claude-sonnet-4-20250514';
|
|
1795
|
-
else if (sdkModel.includes('claude'))
|
|
1796
|
-
claudeModel = sdkModel;
|
|
1797
|
-
converted = {
|
|
1798
|
-
name: meta.name,
|
|
1799
|
-
version: meta.version || '1.0.0',
|
|
1800
|
-
description: meta.description || '',
|
|
1801
|
-
ossaVersion: manifest.apiVersion || 'ossa/v0.4',
|
|
1802
|
-
// Claude Agent SDK configuration
|
|
1803
|
-
sdk: {
|
|
1804
|
-
typescript: {
|
|
1805
|
-
package: '@anthropic-ai/claude-agent-sdk',
|
|
1806
|
-
install: 'npm install @anthropic-ai/claude-agent-sdk',
|
|
1807
|
-
docs: 'https://docs.claude.com/en/api/agent-sdk/typescript',
|
|
1808
|
-
},
|
|
1809
|
-
python: {
|
|
1810
|
-
package: 'claude-agent-sdk',
|
|
1811
|
-
install: 'pip install claude-agent-sdk',
|
|
1812
|
-
docs: 'https://docs.claude.com/en/api/agent-sdk/python',
|
|
1813
|
-
},
|
|
1814
|
-
go: {
|
|
1815
|
-
package: 'github.com/M1n9X/claude-agent-sdk-go',
|
|
1816
|
-
install: 'go get github.com/M1n9X/claude-agent-sdk-go',
|
|
1817
|
-
docs: 'https://github.com/M1n9X/claude-agent-sdk-go',
|
|
1818
|
-
community: true,
|
|
1819
|
-
},
|
|
1820
|
-
rust: {
|
|
1821
|
-
package: 'claude_agent',
|
|
1822
|
-
install: 'cargo add claude_agent',
|
|
1823
|
-
docs: 'https://crates.io/crates/claude_agent',
|
|
1824
|
-
community: true,
|
|
1825
|
-
},
|
|
1826
|
-
},
|
|
1827
|
-
// Agent options (ready to use in SDK)
|
|
1828
|
-
options: {
|
|
1829
|
-
systemPrompt: sdkRole,
|
|
1830
|
-
model: claudeModel,
|
|
1831
|
-
permissionMode,
|
|
1832
|
-
...(builtInTools.length > 0 ? { allowedTools: builtInTools } : {}),
|
|
1833
|
-
...(Object.keys(mcpServers).length > 0 ? { mcpServers } : {}),
|
|
1834
|
-
},
|
|
1835
|
-
// Custom tools (need implementation)
|
|
1836
|
-
...(customTools.length > 0 ? { customTools } : {}),
|
|
1837
|
-
// TypeScript usage
|
|
1838
|
-
usage: {
|
|
1839
|
-
typescript: `import { query } from '@anthropic-ai/claude-agent-sdk';\n\nconst conversation = query({\n prompt: 'Your prompt here',\n options: ${JSON.stringify({ systemPrompt: sdkRole.substring(0, 80) + '...', model: claudeModel, permissionMode }, null, 4)}\n});\n\nfor await (const message of conversation) {\n if (message.type === 'assistant') {\n for (const block of message.message.content) {\n if (block.type === 'text') process.stdout.write(block.text);\n }\n }\n}`,
|
|
1840
|
-
python: `from claude_agent_sdk import query\n\nasync for message in query(\n prompt="Your prompt here",\n options=ClaudeAgentOptions(\n system_prompt=${JSON.stringify(sdkRole.substring(0, 80) + '...')},\n model="${claudeModel}",\n permission_mode="${permissionMode}",\n )\n):\n if message.type == "assistant":\n for block in message.message.content:\n if hasattr(block, "text"):\n print(block.text, end="")`,
|
|
1841
|
-
},
|
|
1842
|
-
};
|
|
1843
|
-
filename = `${meta.name}.claude-agent-sdk.json`;
|
|
1844
|
-
}
|
|
1845
|
-
else {
|
|
1846
|
-
// Delegate to adapter registry (config-only + full adapters with toConfig())
|
|
1847
|
-
initializeAdapters();
|
|
1848
|
-
const adapter = convertRegistry.getAdapter(input.target);
|
|
1849
|
-
if (!adapter) {
|
|
1610
|
+
default:
|
|
1850
1611
|
return errResponse(`Unknown target: ${input.target}`);
|
|
1851
|
-
}
|
|
1852
|
-
try {
|
|
1853
|
-
const result = await adapter.toConfig(manifest);
|
|
1854
|
-
converted = result.config;
|
|
1855
|
-
filename = result.filename;
|
|
1856
|
-
}
|
|
1857
|
-
catch (err) {
|
|
1858
|
-
return errResponse(`toConfig() failed for target "${input.target}": ${err instanceof Error ? err.message : String(err)}`);
|
|
1859
|
-
}
|
|
1860
1612
|
}
|
|
1861
1613
|
// Optionally write to disk
|
|
1862
1614
|
if (input.output_dir) {
|
|
@@ -1878,11 +1630,7 @@ async function handleConvert(args) {
|
|
|
1878
1630
|
content = JSON.stringify(converted, null, 2);
|
|
1879
1631
|
}
|
|
1880
1632
|
fs.writeFileSync(outPath, content, 'utf8');
|
|
1881
|
-
return okResponse({
|
|
1882
|
-
target: input.target,
|
|
1883
|
-
written_to: outPath,
|
|
1884
|
-
content: converted,
|
|
1885
|
-
});
|
|
1633
|
+
return okResponse({ target: input.target, written_to: outPath, content: converted });
|
|
1886
1634
|
}
|
|
1887
1635
|
return okResponse({ target: input.target, filename, content: converted });
|
|
1888
1636
|
}
|
|
@@ -1897,11 +1645,7 @@ async function handleWorkspace(args) {
|
|
|
1897
1645
|
const wsDir = path.join(dir, '.agents-workspace');
|
|
1898
1646
|
const registryDir = path.join(wsDir, 'registry');
|
|
1899
1647
|
if (fs.existsSync(wsDir)) {
|
|
1900
|
-
return okResponse({
|
|
1901
|
-
action: 'init',
|
|
1902
|
-
status: 'already_exists',
|
|
1903
|
-
path: wsDir,
|
|
1904
|
-
});
|
|
1648
|
+
return okResponse({ action: 'init', status: 'already_exists', path: wsDir });
|
|
1905
1649
|
}
|
|
1906
1650
|
fs.mkdirSync(registryDir, { recursive: true });
|
|
1907
1651
|
const wsName = input.name || path.basename(dir);
|
|
@@ -1913,31 +1657,13 @@ async function handleWorkspace(args) {
|
|
|
1913
1657
|
});
|
|
1914
1658
|
fs.writeFileSync(path.join(registryDir, 'index.yaml'), indexYaml);
|
|
1915
1659
|
fs.writeFileSync(path.join(wsDir, 'README.md'), `# OSSA Workspace: ${wsName}\n\nGenerated by OSSA MCP Server.\n\nRun \`ossa workspace discover\` to scan for agents.\n`);
|
|
1916
|
-
return okResponse({
|
|
1917
|
-
action: 'init',
|
|
1918
|
-
status: 'created',
|
|
1919
|
-
path: wsDir,
|
|
1920
|
-
name: wsName,
|
|
1921
|
-
});
|
|
1660
|
+
return okResponse({ action: 'init', status: 'created', path: wsDir, name: wsName });
|
|
1922
1661
|
}
|
|
1923
1662
|
case 'discover': {
|
|
1924
1663
|
// Scan for all *.ossa.yaml manifests
|
|
1925
|
-
const patterns = [
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
'**/.agents/*/manifest.ossa.yaml',
|
|
1929
|
-
];
|
|
1930
|
-
const ignorePatterns = [
|
|
1931
|
-
'**/node_modules/**',
|
|
1932
|
-
'**/dist/**',
|
|
1933
|
-
'**/.git/**',
|
|
1934
|
-
'**/coverage/**',
|
|
1935
|
-
];
|
|
1936
|
-
const files = await fg(patterns, {
|
|
1937
|
-
cwd: dir,
|
|
1938
|
-
ignore: ignorePatterns,
|
|
1939
|
-
absolute: true,
|
|
1940
|
-
});
|
|
1664
|
+
const patterns = ['**/*.ossa.yaml', '**/*.ossa.yml', '**/.agents/*/manifest.ossa.yaml'];
|
|
1665
|
+
const ignorePatterns = ['**/node_modules/**', '**/dist/**', '**/.git/**', '**/coverage/**'];
|
|
1666
|
+
const files = await fg(patterns, { cwd: dir, ignore: ignorePatterns, absolute: true });
|
|
1941
1667
|
const agents = [];
|
|
1942
1668
|
for (const f of files) {
|
|
1943
1669
|
try {
|
|
@@ -1965,12 +1691,7 @@ async function handleWorkspace(args) {
|
|
|
1965
1691
|
workspace: path.basename(dir),
|
|
1966
1692
|
discovered: new Date().toISOString(),
|
|
1967
1693
|
count: agents.length,
|
|
1968
|
-
agents: agents.map((a) => ({
|
|
1969
|
-
name: a.name,
|
|
1970
|
-
version: a.version,
|
|
1971
|
-
kind: a.kind,
|
|
1972
|
-
path: a.path,
|
|
1973
|
-
})),
|
|
1694
|
+
agents: agents.map((a) => ({ name: a.name, version: a.version, kind: a.kind, path: a.path })),
|
|
1974
1695
|
};
|
|
1975
1696
|
fs.writeFileSync(path.join(registryDir, 'index.yaml'), yaml.dump(index));
|
|
1976
1697
|
}
|
|
@@ -1980,18 +1701,10 @@ async function handleWorkspace(args) {
|
|
|
1980
1701
|
const wsDir = path.join(dir, '.agents-workspace');
|
|
1981
1702
|
const indexPath = path.join(wsDir, 'registry', 'index.yaml');
|
|
1982
1703
|
if (!fs.existsSync(indexPath)) {
|
|
1983
|
-
return okResponse({
|
|
1984
|
-
action: 'status',
|
|
1985
|
-
initialized: false,
|
|
1986
|
-
message: 'Run ossa_workspace with action: init first',
|
|
1987
|
-
});
|
|
1704
|
+
return okResponse({ action: 'status', initialized: false, message: 'Run ossa_workspace with action: init first' });
|
|
1988
1705
|
}
|
|
1989
1706
|
const indexContent = yaml.load(fs.readFileSync(indexPath, 'utf8'));
|
|
1990
|
-
return okResponse({
|
|
1991
|
-
action: 'status',
|
|
1992
|
-
initialized: true,
|
|
1993
|
-
workspace: indexContent,
|
|
1994
|
-
});
|
|
1707
|
+
return okResponse({ action: 'status', initialized: true, workspace: indexContent });
|
|
1995
1708
|
}
|
|
1996
1709
|
}
|
|
1997
1710
|
}
|
|
@@ -2001,10 +1714,7 @@ async function handleWorkspace(args) {
|
|
|
2001
1714
|
/** Recursive deep diff — same algorithm as diff.command.ts (DRY) */
|
|
2002
1715
|
function deepDiff(obj1, obj2, prefix = '') {
|
|
2003
1716
|
const changes = [];
|
|
2004
|
-
const allKeys = new Set([
|
|
2005
|
-
...Object.keys(obj1 || {}),
|
|
2006
|
-
...Object.keys(obj2 || {}),
|
|
2007
|
-
]);
|
|
1717
|
+
const allKeys = new Set([...Object.keys(obj1 || {}), ...Object.keys(obj2 || {})]);
|
|
2008
1718
|
for (const key of allKeys) {
|
|
2009
1719
|
const fieldPath = prefix ? `${prefix}.${key}` : key;
|
|
2010
1720
|
const val1 = obj1?.[key];
|
|
@@ -2015,21 +1725,13 @@ function deepDiff(obj1, obj2, prefix = '') {
|
|
|
2015
1725
|
else if (!(key in (obj2 || {}))) {
|
|
2016
1726
|
changes.push({ type: 'removed', path: fieldPath, oldValue: val1 });
|
|
2017
1727
|
}
|
|
2018
|
-
else if (typeof val1 === 'object' &&
|
|
2019
|
-
|
|
2020
|
-
val1
|
|
2021
|
-
val2 !== null &&
|
|
2022
|
-
!Array.isArray(val1) &&
|
|
2023
|
-
!Array.isArray(val2)) {
|
|
1728
|
+
else if (typeof val1 === 'object' && typeof val2 === 'object' &&
|
|
1729
|
+
val1 !== null && val2 !== null &&
|
|
1730
|
+
!Array.isArray(val1) && !Array.isArray(val2)) {
|
|
2024
1731
|
changes.push(...deepDiff(val1, val2, fieldPath));
|
|
2025
1732
|
}
|
|
2026
1733
|
else if (JSON.stringify(val1) !== JSON.stringify(val2)) {
|
|
2027
|
-
changes.push({
|
|
2028
|
-
type: 'modified',
|
|
2029
|
-
path: fieldPath,
|
|
2030
|
-
oldValue: val1,
|
|
2031
|
-
newValue: val2,
|
|
2032
|
-
});
|
|
1734
|
+
changes.push({ type: 'modified', path: fieldPath, oldValue: val1, newValue: val2 });
|
|
2033
1735
|
}
|
|
2034
1736
|
}
|
|
2035
1737
|
return changes;
|
|
@@ -2038,8 +1740,7 @@ function deepDiff(obj1, obj2, prefix = '') {
|
|
|
2038
1740
|
function isBreakingChange(change) {
|
|
2039
1741
|
if (change.type === 'removed')
|
|
2040
1742
|
return true;
|
|
2041
|
-
if (change.path.includes('metadata.name') ||
|
|
2042
|
-
change.path.includes('metadata.version'))
|
|
1743
|
+
if (change.path.includes('metadata.name') || change.path.includes('metadata.version'))
|
|
2043
1744
|
return true;
|
|
2044
1745
|
if (change.path.includes('spec.role'))
|
|
2045
1746
|
return true;
|
|
@@ -2081,13 +1782,8 @@ async function handleMigrate(args) {
|
|
|
2081
1782
|
const detectionResult = await versionDetectionService.detectVersion(manifest);
|
|
2082
1783
|
const currentVersion = detectionResult.version || manifest.apiVersion || 'unknown';
|
|
2083
1784
|
const targetVersion = input.target_version;
|
|
2084
|
-
if (currentVersion === targetVersion ||
|
|
2085
|
-
`
|
|
2086
|
-
return okResponse({
|
|
2087
|
-
migrated: false,
|
|
2088
|
-
reason: `Already at ${targetVersion}`,
|
|
2089
|
-
manifest_path: manifestPath,
|
|
2090
|
-
});
|
|
1785
|
+
if (currentVersion === targetVersion || `ossa/${currentVersion}` === targetVersion) {
|
|
1786
|
+
return okResponse({ migrated: false, reason: `Already at ${targetVersion}`, manifest_path: manifestPath });
|
|
2091
1787
|
}
|
|
2092
1788
|
// Strip 'ossa/' prefix for MigrationTransformService (expects '0.3.3', not 'ossa/v0.3.3')
|
|
2093
1789
|
const fromVer = currentVersion.replace(/^ossa\/v?/, '');
|
|
@@ -2117,26 +1813,11 @@ async function handleMigrate(args) {
|
|
|
2117
1813
|
const outDir = resolvePath(input.output_dir);
|
|
2118
1814
|
fs.mkdirSync(outDir, { recursive: true });
|
|
2119
1815
|
const outPath = path.join(outDir, path.basename(manifestPath));
|
|
2120
|
-
const output = yaml.dump(migrated, {
|
|
2121
|
-
lineWidth: 120,
|
|
2122
|
-
noRefs: true,
|
|
2123
|
-
});
|
|
1816
|
+
const output = yaml.dump(migrated, { lineWidth: 120, noRefs: true });
|
|
2124
1817
|
fs.writeFileSync(outPath, output, 'utf8');
|
|
2125
|
-
return okResponse({
|
|
2126
|
-
migrated: true,
|
|
2127
|
-
from: currentVersion,
|
|
2128
|
-
to: targetVersion,
|
|
2129
|
-
migrations,
|
|
2130
|
-
written_to: outPath,
|
|
2131
|
-
});
|
|
1818
|
+
return okResponse({ migrated: true, from: currentVersion, to: targetVersion, migrations, written_to: outPath });
|
|
2132
1819
|
}
|
|
2133
|
-
return okResponse({
|
|
2134
|
-
migrated: true,
|
|
2135
|
-
from: currentVersion,
|
|
2136
|
-
to: targetVersion,
|
|
2137
|
-
migrations,
|
|
2138
|
-
manifest: migrated,
|
|
2139
|
-
});
|
|
1820
|
+
return okResponse({ migrated: true, from: currentVersion, to: targetVersion, migrations, manifest: migrated });
|
|
2140
1821
|
}
|
|
2141
1822
|
// ---------------------------------------------------------------------------
|
|
2142
1823
|
// Helpers
|
|
@@ -2166,12 +1847,7 @@ function okResponse(data) {
|
|
|
2166
1847
|
}
|
|
2167
1848
|
function errResponse(message) {
|
|
2168
1849
|
return {
|
|
2169
|
-
content: [
|
|
2170
|
-
{
|
|
2171
|
-
type: 'text',
|
|
2172
|
-
text: JSON.stringify({ error: message }, null, 2),
|
|
2173
|
-
},
|
|
2174
|
-
],
|
|
1850
|
+
content: [{ type: 'text', text: JSON.stringify({ error: message }, null, 2) }],
|
|
2175
1851
|
isError: true,
|
|
2176
1852
|
};
|
|
2177
1853
|
}
|