@artinet/cruiser 0.1.5 → 0.1.6

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.
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @fileoverview openclaw → artinet
3
+ *
4
+ * @module @artinet/cruiser/openclaw
5
+ * @description
6
+ * This adapter "docks" OpenClaw Gateway agents into artinet.
7
+ */
8
+ import { Dock, Park } from '../corsair.js';
9
+ import { type OpenClawAgent } from './utils.js';
10
+ /**
11
+ * Configuration options for OpenClaw Gateway WebSocket calls.
12
+ */
13
+ export type OpenClawDockOptions = {
14
+ /**
15
+ * Timeout for WS connect handshake in milliseconds.
16
+ */
17
+ connectTimeoutMs?: number;
18
+ /**
19
+ * Timeout for gateway request completion in milliseconds.
20
+ */
21
+ timeoutMs?: number;
22
+ };
23
+ /**
24
+ * @deprecated Use {@link OpenClawDockOptions} instead.
25
+ */
26
+ export type OpenClawParkOptions = OpenClawDockOptions;
27
+ /**
28
+ * Docks an OpenClaw Gateway agent into artinet.
29
+ *
30
+ * This adapter uses OpenClaw's native Gateway WebSocket protocol.
31
+ *
32
+ * OpenClaw docs:
33
+ * https://docs.openclaw.ai/gateway/protocol
34
+ */
35
+ export declare const dock: Dock<OpenClawAgent, OpenClawDockOptions>;
36
+ /**
37
+ * @deprecated Use {@link dock} instead.
38
+ */
39
+ export declare const park: Park<OpenClawAgent, OpenClawDockOptions>;
40
+ export type { OpenClawAgent } from './utils.js';
@@ -0,0 +1,97 @@
1
+ /**
2
+ * @fileoverview openclaw → artinet
3
+ *
4
+ * @module @artinet/cruiser/openclaw
5
+ * @description
6
+ * This adapter "docks" OpenClaw Gateway agents into artinet.
7
+ */
8
+ import * as sdk from '@artinet/sdk';
9
+ import { OpenClawGatewayClient } from './client.js';
10
+ import { extractOpenClawText, getAgentCard } from './utils.js';
11
+ /**
12
+ * Docks an OpenClaw Gateway agent into artinet.
13
+ *
14
+ * This adapter uses OpenClaw's native Gateway WebSocket protocol.
15
+ *
16
+ * OpenClaw docs:
17
+ * https://docs.openclaw.ai/gateway/protocol
18
+ */
19
+ export const dock = async function dock(agent, card, options) {
20
+ const agentCard = await getAgentCard({ agent, card });
21
+ const gatewayUrl = (agent.gatewayUrl ?? 'ws://127.0.0.1:18789').replace(/\/+$/, '');
22
+ const agentId = agent.agentId ?? 'main';
23
+ const connectTimeoutMs = options?.connectTimeoutMs && options.connectTimeoutMs > 0 ? options.connectTimeoutMs : 10_000;
24
+ const requestTimeoutMs = options?.timeoutMs && options.timeoutMs > 0 ? options.timeoutMs : 60_000;
25
+ const gateway = new OpenClawGatewayClient({
26
+ url: gatewayUrl,
27
+ authToken: agent.authToken,
28
+ authPassword: agent.authPassword,
29
+ agent,
30
+ device: agent.device,
31
+ scopes: agent.scopes,
32
+ connectTimeoutMs,
33
+ });
34
+ await gateway.ensureConnected();
35
+ sdk.logger.debug(`OpenClaw[${agentCard.name}]:[card:${JSON.stringify(agentCard)}]`);
36
+ return sdk.cr8(agentCard).from(async function* (context) {
37
+ sdk.logger.debug(`OpenClaw[${agentCard.name}]:[context:${context.contextId}]: starting`);
38
+ const task = await context.getTask();
39
+ const text = sdk.extractTextContent(context.userMessage);
40
+ if (!text || text.trim().length === 0) {
41
+ yield sdk.describe.update.failed({
42
+ taskId: context.taskId,
43
+ contextId: context.contextId,
44
+ message: sdk.describe.message({
45
+ taskId: context.taskId,
46
+ contextId: context.contextId,
47
+ parts: [sdk.describe.part.text('no input text detected')],
48
+ }),
49
+ });
50
+ return;
51
+ }
52
+ try {
53
+ const result = await gateway.requestAgentRun({
54
+ message: text,
55
+ agentId,
56
+ sessionKey: agent.sessionKey ?? context.contextId,
57
+ timeoutMs: requestTimeoutMs,
58
+ });
59
+ const responseText = extractOpenClawText(result);
60
+ const message = sdk.describe.message({
61
+ taskId: context.taskId,
62
+ contextId: context.contextId,
63
+ parts: [sdk.describe.part.text(responseText)],
64
+ });
65
+ yield sdk.describe.update.completed({
66
+ taskId: context.taskId,
67
+ contextId: context.contextId,
68
+ message,
69
+ metadata: {
70
+ ...(task.metadata ?? {}),
71
+ result,
72
+ },
73
+ });
74
+ }
75
+ catch (error) {
76
+ sdk.logger.error('OpenClaw execution failed', error);
77
+ const errorMessage = error instanceof Error ? error.message : String(error);
78
+ yield sdk.describe.update.failed({
79
+ taskId: context.taskId,
80
+ contextId: context.contextId,
81
+ message: sdk.describe.message({
82
+ taskId: context.taskId,
83
+ contextId: context.contextId,
84
+ parts: [sdk.describe.part.text(`error invoking OpenClaw agent: ${errorMessage}`)],
85
+ metadata: {
86
+ ...(task.metadata ?? {}),
87
+ error: errorMessage,
88
+ },
89
+ }),
90
+ });
91
+ }
92
+ });
93
+ };
94
+ /**
95
+ * @deprecated Use {@link dock} instead.
96
+ */
97
+ export const park = dock;
@@ -0,0 +1,71 @@
1
+ /**
2
+ * @fileoverview openclaw → artinet utils
3
+ *
4
+ * @module @artinet/cruiser/openclaw/utils
5
+ * @internal
6
+ */
7
+ import * as sdk from "@artinet/sdk";
8
+ export type OpenClawTool = {
9
+ name: string;
10
+ description?: string;
11
+ };
12
+ export type OpenClawDeviceIdentity = {
13
+ id: string;
14
+ publicKey: string;
15
+ privateKeyPem?: string;
16
+ signature?: string;
17
+ signedAt?: number;
18
+ nonce?: string;
19
+ };
20
+ export type OpenClawAgent = {
21
+ /**
22
+ * A2A card display name.
23
+ */
24
+ name: string;
25
+ /**
26
+ * Gateway base URL, e.g. http://127.0.0.1:18789
27
+ */
28
+ gatewayUrl?: string;
29
+ /**
30
+ * OpenClaw agent id. Defaults to "main".
31
+ */
32
+ agentId?: string;
33
+ /**
34
+ * Gateway auth token (token mode).
35
+ */
36
+ authToken?: string;
37
+ /**
38
+ * Gateway auth password (password mode).
39
+ */
40
+ authPassword?: string;
41
+ /**
42
+ * Optional fixed session key routed by OpenClaw gateway.
43
+ */
44
+ sessionKey?: string;
45
+ /**
46
+ * Optional explicit device identity for strict pairing setups.
47
+ */
48
+ device?: OpenClawDeviceIdentity;
49
+ /**
50
+ * Optional path where cruiser stores generated OpenClaw device auth state.
51
+ * Defaults to ~/artinet-openclaw.auth when auto device auth is enabled.
52
+ */
53
+ authFilePath?: string;
54
+ /**
55
+ * Enables automatic device identity bootstrap + persisted device token usage.
56
+ * Defaults to true.
57
+ */
58
+ autoDeviceAuth?: boolean;
59
+ /**
60
+ * Optional custom scopes passed during gateway connect.
61
+ */
62
+ scopes?: string[];
63
+ description?: string;
64
+ tools?: OpenClawTool[];
65
+ };
66
+ export declare function getAgentCard({ agent, card, }: {
67
+ agent: OpenClawAgent;
68
+ card?: sdk.A2A.AgentCardParams;
69
+ }): Promise<sdk.A2A.AgentCard>;
70
+ export declare function extractOpenClawText(result: OpenClawResult): string;
71
+ export type OpenClawResult = Record<string, unknown>;
@@ -0,0 +1,90 @@
1
+ /**
2
+ * @fileoverview openclaw → artinet utils
3
+ *
4
+ * @module @artinet/cruiser/openclaw/utils
5
+ * @internal
6
+ */
7
+ import * as sdk from "@artinet/sdk";
8
+ function createSkills(tools) {
9
+ return (tools?.map((tool) => ({
10
+ id: tool.name,
11
+ name: tool.name,
12
+ description: tool.description ?? `Tool: ${tool.name}`,
13
+ tags: ["tool"],
14
+ })) ?? []);
15
+ }
16
+ function createDescription(agent) {
17
+ if (agent.description && agent.description.trim().length > 0) {
18
+ return agent.description.trim();
19
+ }
20
+ return "An OpenClaw Gateway agent connected through @artinet/cruiser";
21
+ }
22
+ export async function getAgentCard({ agent, card, }) {
23
+ return sdk.describe.card({
24
+ name: agent.name,
25
+ ...(typeof card === "string" ? { name: card } : card),
26
+ description: createDescription(agent),
27
+ capabilities: {
28
+ streaming: true,
29
+ pushNotifications: true,
30
+ stateTransitionHistory: false,
31
+ },
32
+ defaultInputModes: ["text"],
33
+ defaultOutputModes: ["text"],
34
+ skills: createSkills(agent.tools),
35
+ });
36
+ }
37
+ function asRecord(value) {
38
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
39
+ return undefined;
40
+ }
41
+ return value;
42
+ }
43
+ export function extractOpenClawText(result) {
44
+ const record = asRecord(result);
45
+ if (!record) {
46
+ return "";
47
+ }
48
+ const payloads = record.payloads;
49
+ if (Array.isArray(payloads)) {
50
+ const text = payloads
51
+ .map((payload) => {
52
+ const entry = asRecord(payload);
53
+ if (typeof entry?.text === "string") {
54
+ return entry.text;
55
+ }
56
+ return "";
57
+ })
58
+ .filter((item) => item.length > 0)
59
+ .join("\n")
60
+ .trim();
61
+ if (text.length > 0) {
62
+ return text;
63
+ }
64
+ }
65
+ const choices = record.choices;
66
+ if (!Array.isArray(choices) || choices.length === 0) {
67
+ return "";
68
+ }
69
+ const firstChoice = asRecord(choices[0]);
70
+ const message = asRecord(firstChoice?.message);
71
+ const content = message?.content;
72
+ if (typeof content === "string") {
73
+ return content;
74
+ }
75
+ if (Array.isArray(content)) {
76
+ return content
77
+ .map((part) => {
78
+ if (typeof part === "string") {
79
+ return part;
80
+ }
81
+ const partRecord = asRecord(part);
82
+ if (typeof partRecord?.text === "string") {
83
+ return partRecord.text;
84
+ }
85
+ return JSON.stringify(part);
86
+ })
87
+ .join("\n");
88
+ }
89
+ return "";
90
+ }
package/package.json CHANGED
@@ -1,142 +1,148 @@
1
1
  {
2
- "name": "@artinet/cruiser",
3
- "version": "0.1.5",
4
- "description": "A library for building A2A enabled runtime Agents.",
5
- "type": "module",
6
- "main": "./dist/index.js",
7
- "module": "./dist/index.js",
8
- "types": "./dist/index.d.ts",
9
- "exports": {
10
- ".": {
11
- "types": "./dist/index.d.ts",
12
- "import": "./dist/index.js",
13
- "default": "./dist/index.js"
2
+ "name": "@artinet/cruiser",
3
+ "version": "0.1.6",
4
+ "description": "A library for building A2A enabled runtime Agents.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "./mastra": {
16
+ "types": "./dist/mastra/index.d.ts",
17
+ "import": "./dist/mastra/index.js",
18
+ "default": "./dist/mastra/index.js"
19
+ },
20
+ "./langchain": {
21
+ "types": "./dist/langchain/index.d.ts",
22
+ "import": "./dist/langchain/index.js",
23
+ "default": "./dist/langchain/index.js"
24
+ },
25
+ "./claude": {
26
+ "types": "./dist/claude/index.d.ts",
27
+ "import": "./dist/claude/index.js",
28
+ "default": "./dist/claude/index.js"
29
+ },
30
+ "./openai": {
31
+ "types": "./dist/openai/index.d.ts",
32
+ "import": "./dist/openai/index.js",
33
+ "default": "./dist/openai/index.js"
34
+ },
35
+ "./strands": {
36
+ "types": "./dist/strands/index.d.ts",
37
+ "import": "./dist/strands/index.js",
38
+ "default": "./dist/strands/index.js"
39
+ },
40
+ "./openclaw": {
41
+ "types": "./dist/openclaw/index.d.ts",
42
+ "import": "./dist/openclaw/index.js",
43
+ "default": "./dist/openclaw/index.js"
44
+ }
14
45
  },
15
- "./mastra": {
16
- "types": "./dist/mastra/index.d.ts",
17
- "import": "./dist/mastra/index.js",
18
- "default": "./dist/mastra/index.js"
46
+ "rootDir": ".",
47
+ "files": [
48
+ "dist",
49
+ "package.json",
50
+ "README.md",
51
+ "LICENSE"
52
+ ],
53
+ "scripts": {
54
+ "build": "tsc --project tsconfig.json",
55
+ "clean": "rimraf dist",
56
+ "rebuild": "rimraf dist node_modules/ package-lock.json && npm i && npm run build",
57
+ "lint": "eslint src --ext .ts",
58
+ "package-test": "npm run build && npm pack && sync && sleep 1 && docker build -f ./deployment/test.dockerfile -t cruiser-test . && docker run --env-file .env --rm cruiser-test && rm artinet-cruiser-*.tgz",
59
+ "prepublishOnly": "rimraf dist && npm run build && npm run lint && npm test",
60
+ "test": "NODE_OPTIONS=--experimental-vm-modules jest",
61
+ "test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch",
62
+ "test:coverage": "NODE_OPTIONS=--experimental-vm-modules jest --coverage"
19
63
  },
20
- "./langchain": {
21
- "types": "./dist/langchain/index.d.ts",
22
- "import": "./dist/langchain/index.js",
23
- "default": "./dist/langchain/index.js"
64
+ "keywords": [
65
+ "agent2agent",
66
+ "a2a",
67
+ "artinet",
68
+ "ai",
69
+ "agent",
70
+ "artificial intelligence",
71
+ "mastra",
72
+ "langchain",
73
+ "claude",
74
+ "openai",
75
+ "strands",
76
+ "openclaw"
77
+ ],
78
+ "author": "artinet",
79
+ "license": "Apache-2.0",
80
+ "repository": {
81
+ "type": "git",
82
+ "url": "git+https://github.com/the-artinet-project/artinet.git"
24
83
  },
25
- "./claude": {
26
- "types": "./dist/claude/index.d.ts",
27
- "import": "./dist/claude/index.js",
28
- "default": "./dist/claude/index.js"
84
+ "bugs": {
85
+ "url": "https://github.com/the-artinet-project/artinet/issues"
29
86
  },
30
- "./openai": {
31
- "types": "./dist/openai/index.d.ts",
32
- "import": "./dist/openai/index.js",
33
- "default": "./dist/openai/index.js"
87
+ "homepage": "https://artinet.io",
88
+ "dependencies": {
89
+ "@artinet/sdk": "^0.6.4",
90
+ "@artinet/types": "^0.1.4",
91
+ "uuid": "^13.0.0"
34
92
  },
35
- "./strands": {
36
- "types": "./dist/strands/index.d.ts",
37
- "import": "./dist/strands/index.js",
38
- "default": "./dist/strands/index.js"
39
- }
40
- },
41
- "rootDir": ".",
42
- "files": [
43
- "dist",
44
- "package.json",
45
- "README.md",
46
- "LICENSE"
47
- ],
48
- "scripts": {
49
- "build": "tsc --project tsconfig.json",
50
- "clean": "rimraf dist",
51
- "rebuild": "rimraf dist node_modules/ package-lock.json && npm i && npm run build",
52
- "lint": "eslint src --ext .ts",
53
- "package-test": "npm run build && npm pack && sync && sleep 1 && docker build -f ./deployment/test.dockerfile -t cruiser-test . && docker run --env-file .env --rm cruiser-test && rm artinet-cruiser-*.tgz",
54
- "prepublishOnly": "rimraf dist && npm run build && npm run lint && npm test",
55
- "test": "NODE_OPTIONS=--experimental-vm-modules jest",
56
- "test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch",
57
- "test:coverage": "NODE_OPTIONS=--experimental-vm-modules jest --coverage"
58
- },
59
- "keywords": [
60
- "agent2agent",
61
- "a2a",
62
- "artinet",
63
- "ai",
64
- "agent",
65
- "artificial intelligence",
66
- "mastra",
67
- "langchain",
68
- "claude",
69
- "openai",
70
- "strands"
71
- ],
72
- "author": "artinet",
73
- "license": "Apache-2.0",
74
- "repository": {
75
- "type": "git",
76
- "url": "git+https://github.com/the-artinet-project/artinet.git"
77
- },
78
- "bugs": {
79
- "url": "https://github.com/the-artinet-project/artinet/issues"
80
- },
81
- "homepage": "https://artinet.io",
82
- "dependencies": {
83
- "@artinet/sdk": "^0.6.4",
84
- "@artinet/types": "^0.1.4",
85
- "uuid": "^13.0.0"
86
- },
87
- "peerDependencies": {
88
- "@a2a-js/sdk": "^0.3.7",
89
- "@anthropic-ai/claude-agent-sdk": "^0.2.2",
90
- "@anthropic-ai/sdk": "^0.71.2",
91
- "@mastra/core": "^0.24.9",
92
- "@mastra/server": "^0.24.9",
93
- "@modelcontextprotocol/sdk": "^1.24.3",
94
- "@strands-agents/sdk": "^0.1.4",
95
- "express": "^5.1.0",
96
- "langchain": "^1.2.7",
97
- "openai": "^6.15.0"
98
- },
99
- "peerDependenciesMeta": {
100
- "@a2a-js/sdk": {
101
- "optional": false
93
+ "peerDependencies": {
94
+ "@a2a-js/sdk": "^0.3.7",
95
+ "@anthropic-ai/claude-agent-sdk": "^0.2.2",
96
+ "@anthropic-ai/sdk": "^0.71.2",
97
+ "@mastra/core": "^0.24.9",
98
+ "@mastra/server": "^0.24.9",
99
+ "@modelcontextprotocol/sdk": "^1.24.3",
100
+ "@strands-agents/sdk": "^0.1.4",
101
+ "express": "^5.1.0",
102
+ "langchain": "^1.2.7",
103
+ "openai": "^6.15.0"
104
+ },
105
+ "peerDependenciesMeta": {
106
+ "@a2a-js/sdk": {
107
+ "optional": false
108
+ },
109
+ "express": {
110
+ "optional": false
111
+ },
112
+ "@modelcontextprotocol/sdk": {
113
+ "optional": false
114
+ }
115
+ },
116
+ "devDependencies": {
117
+ "@openrouter/ai-sdk-provider": "^1.5.4",
118
+ "@a2a-js/sdk": "^0.3.7",
119
+ "@anthropic-ai/claude-agent-sdk": "^0.2.2",
120
+ "@anthropic-ai/sdk": "^0.71.2",
121
+ "@eslint/js": "^9.39.2",
122
+ "@langchain/openai": "^1.2.1",
123
+ "@mastra/core": "^1.4.0",
124
+ "@mastra/server": "^1.4.0",
125
+ "@openai/agents": "^0.3.7",
126
+ "@strands-agents/sdk": "^0.1.4",
127
+ "@types/jest": "^29.5.14",
128
+ "@types/node": "^25.0.9",
129
+ "@types/uuid": "^10.0.0",
130
+ "ai": "^5.0.10",
131
+ "eslint": "^9.39.2",
132
+ "globals": "^17.0.0",
133
+ "jest": "29.7.0",
134
+ "langchain": "^1.2.10",
135
+ "rimraf": "^6.1.2",
136
+ "ts-jest": "^29.4.6",
137
+ "ts-node": "^10.9.2",
138
+ "tsx": "^4.21.0",
139
+ "typescript": "^5.9.3",
140
+ "typescript-eslint": "^8.53.0"
102
141
  },
103
- "express": {
104
- "optional": false
142
+ "engines": {
143
+ "node": ">=20.0.0"
105
144
  },
106
- "@modelcontextprotocol/sdk": {
107
- "optional": false
145
+ "directories": {
146
+ "test": "tests"
108
147
  }
109
- },
110
- "devDependencies": {
111
- "@openrouter/ai-sdk-provider": "^1.5.4",
112
- "@a2a-js/sdk": "^0.3.7",
113
- "@anthropic-ai/claude-agent-sdk": "^0.2.2",
114
- "@anthropic-ai/sdk": "^0.71.2",
115
- "@eslint/js": "^9.39.2",
116
- "@langchain/openai": "^1.2.1",
117
- "@mastra/core": "^0.24.9",
118
- "@mastra/server": "^2.0.4",
119
- "@openai/agents": "^0.3.7",
120
- "@strands-agents/sdk": "^0.1.4",
121
- "@types/jest": "^29.5.14",
122
- "@types/node": "^25.0.9",
123
- "@types/uuid": "^10.0.0",
124
- "ai": "^5.0.10",
125
- "eslint": "^9.39.2",
126
- "globals": "^17.0.0",
127
- "jest": "29.7.0",
128
- "langchain": "^1.2.10",
129
- "rimraf": "^6.1.2",
130
- "ts-jest": "^29.4.6",
131
- "ts-node": "^10.9.2",
132
- "tsx": "^4.21.0",
133
- "typescript": "^5.9.3",
134
- "typescript-eslint": "^8.53.0"
135
- },
136
- "engines": {
137
- "node": ">=20.0.0"
138
- },
139
- "directories": {
140
- "test": "tests"
141
- }
142
148
  }