feat(FN-2260): merge fusion/fn-2260
This commit is contained in:
57
plugins/fusion-plugin-paperclip-runtime/README.md
Normal file
57
plugins/fusion-plugin-paperclip-runtime/README.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# Paperclip Runtime Plugin
|
||||
|
||||
A Fusion plugin that provides the Paperclip runtime for AI agents. Paperclip enables AI agents to browse web pages and extract content through a headless browser interface.
|
||||
|
||||
## Status
|
||||
|
||||
> **Note:** This plugin is currently a scaffold with a placeholder runtime. Full Paperclip runtime implementation is deferred to FN-2261.
|
||||
|
||||
## Installation
|
||||
|
||||
This plugin is installed as a local plugin:
|
||||
|
||||
```bash
|
||||
fn plugin add ./plugins/fusion-plugin-paperclip-runtime
|
||||
```
|
||||
|
||||
## Runtime Capabilities
|
||||
|
||||
When fully implemented, this runtime will provide:
|
||||
|
||||
- **Web Page Browsing**: Navigate to URLs and retrieve page content
|
||||
- **Content Extraction**: Extract specific information from web pages using CSS selectors or XPath
|
||||
- **Form Interaction**: Fill and submit web forms
|
||||
- **JavaScript Rendering**: Execute JavaScript to render dynamic content
|
||||
|
||||
## Development
|
||||
|
||||
### Build
|
||||
|
||||
```bash
|
||||
pnpm --filter ./plugins/fusion-plugin-paperclip-runtime build
|
||||
```
|
||||
|
||||
### Test
|
||||
|
||||
```bash
|
||||
pnpm --filter ./plugins/fusion-plugin-paperclip-runtime test
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
This plugin follows the Fusion plugin runtime contract defined in FN-2256. It registers a runtime factory that creates Paperclip runtime instances on demand.
|
||||
|
||||
### Runtime Contract
|
||||
|
||||
- **Runtime ID**: `paperclip`
|
||||
- **Factory**: `PluginRuntimeFactory` from `@fusion/plugin-sdk`
|
||||
|
||||
## Deferred Work
|
||||
|
||||
Full runtime implementation including:
|
||||
- Browser automation setup
|
||||
- Content extraction logic
|
||||
- Session management
|
||||
- Error handling and retry logic
|
||||
|
||||
These are tracked in [FN-2261](https://github.com/gsxdsm/fusion/issues/FN-2261).
|
||||
15
plugins/fusion-plugin-paperclip-runtime/manifest.json
Normal file
15
plugins/fusion-plugin-paperclip-runtime/manifest.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"id": "fusion-plugin-paperclip-runtime",
|
||||
"name": "Paperclip Runtime Plugin",
|
||||
"version": "0.1.0",
|
||||
"description": "Provides Paperclip web access runtime for Fusion AI agents",
|
||||
"author": "Fusion Team",
|
||||
"homepage": "https://github.com/gsxdsm/fusion",
|
||||
"fusionVersion": ">=0.1.0",
|
||||
"runtime": {
|
||||
"runtimeId": "paperclip",
|
||||
"name": "Paperclip Runtime",
|
||||
"description": "Web access runtime for AI agents — browse pages and extract content",
|
||||
"version": "0.1.0"
|
||||
}
|
||||
}
|
||||
27
plugins/fusion-plugin-paperclip-runtime/package.json
Normal file
27
plugins/fusion-plugin-paperclip-runtime/package.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "@fusion-plugin-examples/paperclip-runtime",
|
||||
"version": "0.1.0",
|
||||
"type": "module",
|
||||
"description": "Paperclip runtime plugin for Fusion — provides AI agent web access capabilities",
|
||||
"keywords": [
|
||||
"fusion-plugin"
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./src/index.ts",
|
||||
"import": "./dist/index.js"
|
||||
}
|
||||
},
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test": "vitest run --silent=passed-only --reporter=dot"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fusion/plugin-sdk": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^25.5.2",
|
||||
"vitest": "^3.2.4"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import plugin from "../index.js";
|
||||
|
||||
// ── Test Suite ─────────────────────────────────────────────────────────────────
|
||||
|
||||
describe("paperclip-runtime plugin", () => {
|
||||
describe("plugin manifest identity", () => {
|
||||
it("should export a valid FusionPlugin with correct manifest fields", () => {
|
||||
expect(plugin.manifest.id).toBe("fusion-plugin-paperclip-runtime");
|
||||
expect(plugin.manifest.name).toBe("Paperclip Runtime Plugin");
|
||||
expect(plugin.manifest.version).toBe("0.1.0");
|
||||
expect(plugin.manifest.description).toBe(
|
||||
"Provides Paperclip web access runtime for Fusion AI agents",
|
||||
);
|
||||
expect(plugin.manifest.author).toBe("Fusion Team");
|
||||
expect(plugin.state).toBe("installed");
|
||||
});
|
||||
|
||||
it("should have runtime manifest metadata matching manifest.json", () => {
|
||||
expect(plugin.manifest.runtime).toBeDefined();
|
||||
expect(plugin.manifest.runtime!.runtimeId).toBe("paperclip");
|
||||
expect(plugin.manifest.runtime!.name).toBe("Paperclip Runtime");
|
||||
expect(plugin.manifest.runtime!.version).toBe("0.1.0");
|
||||
});
|
||||
|
||||
it("should have fusionVersion requirement", () => {
|
||||
expect(plugin.manifest.fusionVersion).toBe(">=0.1.0");
|
||||
});
|
||||
});
|
||||
|
||||
describe("runtime placeholder registration", () => {
|
||||
it("should have runtime registration", () => {
|
||||
expect(plugin.runtime).toBeDefined();
|
||||
});
|
||||
|
||||
it("should have correct runtime metadata", () => {
|
||||
const runtime = plugin.runtime!;
|
||||
expect(runtime.metadata.runtimeId).toBe("paperclip");
|
||||
expect(runtime.metadata.name).toBe("Paperclip Runtime");
|
||||
expect(runtime.metadata.version).toBe("0.1.0");
|
||||
});
|
||||
|
||||
it("should have a factory function", () => {
|
||||
expect(plugin.runtime!.factory).toBeDefined();
|
||||
expect(typeof plugin.runtime!.factory).toBe("function");
|
||||
});
|
||||
});
|
||||
|
||||
describe("runtime placeholder invocation", () => {
|
||||
it("should throw deterministic error with FN-2261 reference when factory is invoked", async () => {
|
||||
const factory = plugin.runtime!.factory;
|
||||
|
||||
await expect(factory({} as any)).rejects.toThrow(
|
||||
"Paperclip runtime implementation is deferred to FN-2261",
|
||||
);
|
||||
});
|
||||
|
||||
it("should throw error with placeholder message in the error text", async () => {
|
||||
const factory = plugin.runtime!.factory;
|
||||
|
||||
try {
|
||||
await factory({} as any);
|
||||
expect.fail("Expected factory to throw an error");
|
||||
} catch (error) {
|
||||
expect((error as Error).message).toContain("placeholder");
|
||||
expect((error as Error).message).toContain("FN-2261");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("hooks", () => {
|
||||
it("should have onLoad hook", () => {
|
||||
expect(plugin.hooks.onLoad).toBeDefined();
|
||||
expect(typeof plugin.hooks.onLoad).toBe("function");
|
||||
});
|
||||
|
||||
it("onLoad should not throw when called with valid context", () => {
|
||||
const mockLogger = {
|
||||
info: () => {},
|
||||
warn: () => {},
|
||||
error: () => {},
|
||||
debug: () => {},
|
||||
};
|
||||
const mockCtx = {
|
||||
pluginId: "fusion-plugin-paperclip-runtime",
|
||||
settings: {},
|
||||
logger: mockLogger,
|
||||
emitEvent: () => {},
|
||||
taskStore: {},
|
||||
};
|
||||
|
||||
expect(() => plugin.hooks.onLoad!(mockCtx as any)).not.toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
82
plugins/fusion-plugin-paperclip-runtime/src/index.ts
Normal file
82
plugins/fusion-plugin-paperclip-runtime/src/index.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* Paperclip Runtime Plugin
|
||||
*
|
||||
* Provides the Paperclip web access runtime for Fusion AI agents.
|
||||
* This is a placeholder implementation — full runtime behavior is deferred to FN-2261.
|
||||
*/
|
||||
|
||||
import { definePlugin } from "@fusion/plugin-sdk";
|
||||
import type {
|
||||
FusionPlugin,
|
||||
PluginRuntimeRegistration,
|
||||
} from "@fusion/plugin-sdk";
|
||||
|
||||
// ── Runtime Placeholder ────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Deferred implementation error message for Paperclip runtime.
|
||||
* This message is thrown when the runtime factory is invoked before
|
||||
* full implementation is complete (FN-2261).
|
||||
*/
|
||||
const DEFERRED_ERROR_MESSAGE =
|
||||
"Paperclip runtime implementation is deferred to FN-2261. " +
|
||||
"This is a placeholder plugin — runtime creation is not yet available.";
|
||||
|
||||
/**
|
||||
* Paperclip runtime factory placeholder.
|
||||
*
|
||||
* Throws a deterministic error indicating that the full Paperclip runtime
|
||||
* implementation has not been completed yet.
|
||||
*
|
||||
* @throws Error with DEFERRED_ERROR_MESSAGE when invoked
|
||||
*/
|
||||
async function paperclipRuntimeFactory(): Promise<never> {
|
||||
throw new Error(DEFERRED_ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Paperclip runtime registration for Fusion's plugin runtime system.
|
||||
* Uses the PluginRuntimeRegistration contract from FN-2256.
|
||||
*/
|
||||
const paperclipRuntime: PluginRuntimeRegistration = {
|
||||
metadata: {
|
||||
runtimeId: "paperclip",
|
||||
name: "Paperclip Runtime",
|
||||
description:
|
||||
"Web access runtime for AI agents — browse pages and extract content using headless browser automation",
|
||||
version: "0.1.0",
|
||||
},
|
||||
factory: paperclipRuntimeFactory,
|
||||
};
|
||||
|
||||
// ── Plugin Definition ─────────────────────────────────────────────────────────
|
||||
|
||||
const plugin: FusionPlugin = definePlugin({
|
||||
manifest: {
|
||||
id: "fusion-plugin-paperclip-runtime",
|
||||
name: "Paperclip Runtime Plugin",
|
||||
version: "0.1.0",
|
||||
description: "Provides Paperclip web access runtime for Fusion AI agents",
|
||||
author: "Fusion Team",
|
||||
homepage: "https://github.com/gsxdsm/fusion",
|
||||
fusionVersion: ">=0.1.0",
|
||||
runtime: {
|
||||
runtimeId: "paperclip",
|
||||
name: "Paperclip Runtime",
|
||||
description:
|
||||
"Web access runtime for AI agents — browse pages and extract content",
|
||||
version: "0.1.0",
|
||||
},
|
||||
},
|
||||
state: "installed",
|
||||
runtime: paperclipRuntime,
|
||||
hooks: {
|
||||
onLoad: (ctx) => {
|
||||
ctx.logger.info(
|
||||
"Paperclip Runtime Plugin loaded (placeholder — implementation deferred to FN-2261)",
|
||||
);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default plugin;
|
||||
9
plugins/fusion-plugin-paperclip-runtime/tsconfig.json
Normal file
9
plugins/fusion-plugin-paperclip-runtime/tsconfig.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"rootDir": "src",
|
||||
"types": ["node", "vitest/globals"]
|
||||
},
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
14
plugins/fusion-plugin-paperclip-runtime/vitest.config.ts
Normal file
14
plugins/fusion-plugin-paperclip-runtime/vitest.config.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { defineConfig } from "vitest/config";
|
||||
|
||||
const requestedMaxWorkers = Number.parseInt(process.env.VITEST_MAX_WORKERS ?? "2", 10);
|
||||
const maxWorkers = Math.max(1, Math.min(2, Number.isFinite(requestedMaxWorkers) ? requestedMaxWorkers : 2));
|
||||
process.env.VITEST_MAX_WORKERS = String(maxWorkers);
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
include: ["src/**/*.test.ts"],
|
||||
pool: "threads",
|
||||
maxWorkers,
|
||||
poolOptions: { threads: { minThreads: 1, maxThreads: maxWorkers }, forks: { minForks: 1, maxForks: maxWorkers } },
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user