agent-portal-2 0.1.0

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.
Files changed (120) hide show
  1. package/.continue/agents/new-config.yaml +22 -0
  2. package/AGENT_STEERING.md +36 -0
  3. package/ARCHITECTURE.md +13 -0
  4. package/CHANGELOG.md +97 -0
  5. package/CLI.md +38 -0
  6. package/CONTRIBUTING.md +55 -0
  7. package/INSTALLATION.md +58 -0
  8. package/LICENSE +60 -0
  9. package/PLUGIN_SYSTEM.md +33 -0
  10. package/PYTHON_SDK.md +22 -0
  11. package/QUICKSTART.md +19 -0
  12. package/README.md +385 -0
  13. package/RELEASE_NOTES_v0.1.0.md +281 -0
  14. package/ROADMAP.md +3 -0
  15. package/RUNTIME.md +44 -0
  16. package/SAFETY_MODEL.md +24 -0
  17. package/TESTING.md +35 -0
  18. package/TROUBLESHOOTING.md +30 -0
  19. package/UPGRADE_GUIDE.md +288 -0
  20. package/VS_CODE_EXTENSION.md +47 -0
  21. package/agent-portal.config.json +20 -0
  22. package/apps/desktop/agent-portal-desktop.zip +0 -0
  23. package/apps/desktop/fixtures/local-workflow.html +151 -0
  24. package/apps/desktop/package.json +18 -0
  25. package/apps/desktop/src/main.ts +117 -0
  26. package/apps/desktop/tsconfig.json +8 -0
  27. package/apps/vscode-extension/LICENSE +60 -0
  28. package/apps/vscode-extension/README.md +20 -0
  29. package/apps/vscode-extension/media/agent-portal-logo.png +0 -0
  30. package/apps/vscode-extension/package.json +149 -0
  31. package/apps/vscode-extension/src/extension.ts +614 -0
  32. package/apps/vscode-extension/tsconfig.json +12 -0
  33. package/assets/branding/agent-portal-logo.png +0 -0
  34. package/connectors/chatgpt-tools/README.md +9 -0
  35. package/connectors/claude-mcp-server/README.md +9 -0
  36. package/connectors/gemini-connector/README.md +9 -0
  37. package/connectors/rest-websocket-api/README.md +9 -0
  38. package/docs/MCP_SERVER.md +68 -0
  39. package/docs/architecture.md +214 -0
  40. package/docs/roadmap.md +125 -0
  41. package/package.json +21 -0
  42. package/packages/agent-portal-mcp/README.md +12 -0
  43. package/packages/agent-portal-mcp/agent_portal_mcp/__init__.py +3 -0
  44. package/packages/agent-portal-mcp/agent_portal_mcp/bridge/__init__.py +1 -0
  45. package/packages/agent-portal-mcp/agent_portal_mcp/bridge/runtime_client.py +180 -0
  46. package/packages/agent-portal-mcp/agent_portal_mcp/cli.py +32 -0
  47. package/packages/agent-portal-mcp/agent_portal_mcp/doctor.py +71 -0
  48. package/packages/agent-portal-mcp/agent_portal_mcp/schemas/__init__.py +1 -0
  49. package/packages/agent-portal-mcp/agent_portal_mcp/schemas/actions.py +17 -0
  50. package/packages/agent-portal-mcp/agent_portal_mcp/schemas/results.py +24 -0
  51. package/packages/agent-portal-mcp/agent_portal_mcp/schemas/risk.py +20 -0
  52. package/packages/agent-portal-mcp/agent_portal_mcp/security/__init__.py +1 -0
  53. package/packages/agent-portal-mcp/agent_portal_mcp/security/policy.py +27 -0
  54. package/packages/agent-portal-mcp/agent_portal_mcp/server.py +148 -0
  55. package/packages/agent-portal-mcp/agent_portal_mcp/tool_registry.py +58 -0
  56. package/packages/agent-portal-mcp/agent_portal_mcp/tools/__init__.py +1 -0
  57. package/packages/agent-portal-mcp/agent_portal_mcp/tools/browser.py +89 -0
  58. package/packages/agent-portal-mcp/agent_portal_mcp/tools/common.py +98 -0
  59. package/packages/agent-portal-mcp/agent_portal_mcp/tools/inspection.py +93 -0
  60. package/packages/agent-portal-mcp/agent_portal_mcp/tools/navigation.py +93 -0
  61. package/packages/agent-portal-mcp/agent_portal_mcp/tools/reports.py +34 -0
  62. package/packages/agent-portal-mcp/agent_portal_mcp/tools/steering.py +93 -0
  63. package/packages/agent-portal-mcp/pyproject.toml +20 -0
  64. package/packages/agent-portal-mcp/tests/test_doctor.py +20 -0
  65. package/packages/agent-portal-mcp/tests/test_mcp_server.py +161 -0
  66. package/packages/core/package.json +15 -0
  67. package/packages/core/src/index.ts +1842 -0
  68. package/packages/core/tsconfig.json +8 -0
  69. package/packages/mcp-server/package.json +15 -0
  70. package/packages/mcp-server/src/index.ts +73 -0
  71. package/packages/mcp-server/tsconfig.json +8 -0
  72. package/packages/sdk/package.json +15 -0
  73. package/packages/sdk/src/index.ts +544 -0
  74. package/packages/sdk/tsconfig.json +8 -0
  75. package/plugins/README.md +16 -0
  76. package/plugins/agent-portal-browser/plugin.json +19 -0
  77. package/plugins/agent-portal-python/plugin.json +16 -0
  78. package/plugins/agent-portal-skills/plugin.json +19 -0
  79. package/plugins/agent-portal-vscode/plugin.json +27 -0
  80. package/plugins/example-runtime-plugin/README.md +3 -0
  81. package/plugins/example-runtime-plugin/plugin.json +20 -0
  82. package/plugins/plugin.schema.json +53 -0
  83. package/python/README.md +18 -0
  84. package/python/agent_portal/__init__.py +5 -0
  85. package/python/agent_portal/__main__.py +5 -0
  86. package/python/agent_portal/browser.py +393 -0
  87. package/python/agent_portal/cli.py +164 -0
  88. package/python/agent_portal/config.py +31 -0
  89. package/python/agent_portal/doctor.py +165 -0
  90. package/python/agent_portal/exceptions.py +39 -0
  91. package/python/agent_portal/logging_utils.py +33 -0
  92. package/python/agent_portal/metrics.py +309 -0
  93. package/python/agent_portal/models.py +160 -0
  94. package/python/agent_portal/plugin_system.py +42 -0
  95. package/python/agent_portal/rate_limit.py +253 -0
  96. package/python/agent_portal/runtime.py +739 -0
  97. package/python/agent_portal/server.py +351 -0
  98. package/python/agent_portal/validation.py +299 -0
  99. package/python/pyproject.toml +29 -0
  100. package/python/tests/test_config.py +24 -0
  101. package/python/tests/test_doctor.py +19 -0
  102. package/python/tests/test_metrics.py +180 -0
  103. package/python/tests/test_rate_limit.py +237 -0
  104. package/python/tests/test_runtime.py +122 -0
  105. package/python/tests/test_server.py +53 -0
  106. package/python/tests/test_validation.py +170 -0
  107. package/releases/desktop/agent-portal-desktop/README.md +378 -0
  108. package/releases/desktop/agent-portal-desktop/RELEASE_NOTES.md +14 -0
  109. package/releases/desktop/agent-portal-desktop/assets/branding/agent-portal-logo.png +0 -0
  110. package/releases/desktop/agent-portal-desktop/fixtures/local-workflow.html +151 -0
  111. package/releases/desktop/agent-portal-desktop/launch-agent-portal.bat +4 -0
  112. package/releases/desktop/agent-portal-desktop.zip +0 -0
  113. package/releases/python/agent_portal-0.0.2-py3-none-any.whl +0 -0
  114. package/releases/python/agent_portal-0.0.2.tar.gz +0 -0
  115. package/scripts/package_desktop.mjs +117 -0
  116. package/scripts/release_python.py +46 -0
  117. package/tests/plugin-manifest.test.mjs +26 -0
  118. package/tests/runtime.test.mjs +41 -0
  119. package/tests/vscode-extension.test.mjs +22 -0
  120. package/tsconfig.base.json +16 -0
@@ -0,0 +1,151 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Agent Portal Local Workflow</title>
7
+ <style>
8
+ :root {
9
+ color-scheme: dark;
10
+ --bg: #05070c;
11
+ --panel: #0f1623;
12
+ --line: rgba(255, 255, 255, 0.1);
13
+ --text: #eef3ff;
14
+ --muted: #9cb2d1;
15
+ --blue: #3cc8ff;
16
+ --orange: #ff9a1f;
17
+ }
18
+
19
+ * {
20
+ box-sizing: border-box;
21
+ }
22
+
23
+ body {
24
+ margin: 0;
25
+ min-height: 100vh;
26
+ display: grid;
27
+ place-items: center;
28
+ background:
29
+ radial-gradient(circle at top left, rgba(60, 200, 255, 0.2), transparent 28%),
30
+ radial-gradient(circle at top right, rgba(255, 154, 31, 0.2), transparent 30%),
31
+ linear-gradient(180deg, #070b12, var(--bg));
32
+ color: var(--text);
33
+ font-family: "Segoe UI", system-ui, sans-serif;
34
+ }
35
+
36
+ .panel {
37
+ width: min(92vw, 720px);
38
+ padding: 40px;
39
+ border: 1px solid var(--line);
40
+ border-radius: 28px;
41
+ background: linear-gradient(180deg, rgba(15, 22, 35, 0.96), rgba(7, 11, 18, 0.98));
42
+ box-shadow: 0 30px 80px rgba(0, 0, 0, 0.45);
43
+ }
44
+
45
+ .eyebrow {
46
+ font-size: 12px;
47
+ letter-spacing: 0.24em;
48
+ text-transform: uppercase;
49
+ color: var(--blue);
50
+ }
51
+
52
+ h1 {
53
+ margin: 12px 0 8px;
54
+ font-size: clamp(2rem, 5vw, 3.4rem);
55
+ }
56
+
57
+ p {
58
+ margin: 0 0 24px;
59
+ color: var(--muted);
60
+ line-height: 1.6;
61
+ }
62
+
63
+ form {
64
+ display: grid;
65
+ gap: 14px;
66
+ }
67
+
68
+ label {
69
+ font-size: 0.95rem;
70
+ }
71
+
72
+ input {
73
+ width: 100%;
74
+ padding: 14px 16px;
75
+ border: 1px solid rgba(60, 200, 255, 0.32);
76
+ border-radius: 14px;
77
+ background: rgba(7, 11, 18, 0.85);
78
+ color: var(--text);
79
+ font: inherit;
80
+ }
81
+
82
+ button {
83
+ padding: 14px 18px;
84
+ border: 0;
85
+ border-radius: 14px;
86
+ background: linear-gradient(90deg, var(--blue), var(--orange));
87
+ color: #061019;
88
+ font: inherit;
89
+ font-weight: 700;
90
+ cursor: pointer;
91
+ }
92
+
93
+ .result {
94
+ margin-top: 20px;
95
+ padding: 16px;
96
+ border-radius: 16px;
97
+ border: 1px solid rgba(255, 154, 31, 0.24);
98
+ background: rgba(255, 154, 31, 0.08);
99
+ }
100
+
101
+ .spacer {
102
+ height: 70vh;
103
+ }
104
+
105
+ .evidence {
106
+ margin-top: 24px;
107
+ padding: 20px;
108
+ border-radius: 18px;
109
+ border: 1px solid rgba(60, 200, 255, 0.24);
110
+ background: rgba(60, 200, 255, 0.08);
111
+ }
112
+ </style>
113
+ </head>
114
+ <body>
115
+ <main class="panel">
116
+ <div class="eyebrow">Local Proving Ground</div>
117
+ <h1>See, Act, Record</h1>
118
+ <p>
119
+ This local page exists to prove the Agent Portal browser loop against a
120
+ controlled app inside the repository.
121
+ </p>
122
+ <form id="workflow-form">
123
+ <label for="name">Agent Name</label>
124
+ <input id="name" name="name" type="text" placeholder="Portal Runner" />
125
+ <button id="generate-report" type="submit">Generate Result</button>
126
+ </form>
127
+ <div id="result" class="result" aria-live="polite">
128
+ Waiting for the agent to complete the workflow.
129
+ </div>
130
+ <div class="spacer" aria-hidden="true"></div>
131
+ <section id="evidence-panel" class="evidence">
132
+ <strong>Evidence Panel</strong>
133
+ <p>
134
+ If the agent reached this section, scrolling worked as part of the
135
+ browser automation flow.
136
+ </p>
137
+ </section>
138
+ </main>
139
+ <script>
140
+ const form = document.getElementById("workflow-form");
141
+ const result = document.getElementById("result");
142
+ const input = document.getElementById("name");
143
+
144
+ form.addEventListener("submit", (event) => {
145
+ event.preventDefault();
146
+ const value = input.value.trim() || "Unknown Agent";
147
+ result.textContent = `Workflow completed for ${value}. Screenshot and report are ready.`;
148
+ });
149
+ </script>
150
+ </body>
151
+ </html>
@@ -0,0 +1,4 @@
1
+ @echo off
2
+ setlocal
3
+ cd /d "%~dp0"
4
+ node dist\main.js
@@ -0,0 +1,117 @@
1
+ import { copyFile, mkdir, readdir, readFile, rm, stat, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { execFile } from "node:child_process";
4
+ import { promisify } from "node:util";
5
+
6
+ const execFileAsync = promisify(execFile);
7
+
8
+ const repoRoot = process.cwd();
9
+ const desktopRoot = path.join(repoRoot, "apps", "desktop");
10
+ const stagingRoot = path.join(repoRoot, "releases", "desktop", "agent-portal-desktop");
11
+ const outputDir = path.join(repoRoot, "releases", "desktop");
12
+ const archivePath = path.join(outputDir, "agent-portal-desktop.zip");
13
+
14
+ async function main() {
15
+ await ensureDesktopBuild();
16
+ await rm(stagingRoot, { recursive: true, force: true });
17
+ await mkdir(stagingRoot, { recursive: true });
18
+
19
+ await copyTree(path.join(desktopRoot, "dist"), path.join(stagingRoot, "dist"));
20
+ await copyTree(path.join(desktopRoot, "fixtures"), path.join(stagingRoot, "fixtures"));
21
+ await copyTree(path.join(repoRoot, "assets", "branding"), path.join(stagingRoot, "assets", "branding"));
22
+ await copyOptionalTree(
23
+ path.join(repoRoot, "workspaces", "runtime"),
24
+ path.join(stagingRoot, "runtime-workspaces")
25
+ );
26
+ await copyFile(path.join(repoRoot, "README.md"), path.join(stagingRoot, "README.md"));
27
+ await writeLaunchScript();
28
+ await writeReleaseNotes();
29
+ await zipWithPowerShell(stagingRoot, archivePath);
30
+
31
+ console.log(`Desktop release package written to ${archivePath}`);
32
+ }
33
+
34
+ async function ensureDesktopBuild() {
35
+ await execFileAsync("npm", ["run", "build", "--workspace", "@agent-portal/desktop"], {
36
+ cwd: repoRoot,
37
+ shell: process.platform === "win32"
38
+ });
39
+ }
40
+
41
+ async function copyOptionalTree(source, destination) {
42
+ try {
43
+ await stat(source);
44
+ await copyTree(source, destination);
45
+ } catch {
46
+ return;
47
+ }
48
+ }
49
+
50
+ async function copyTree(source, destination) {
51
+ const sourceStats = await stat(source);
52
+ if (!sourceStats.isDirectory()) {
53
+ throw new Error(`Expected directory: ${source}`);
54
+ }
55
+
56
+ await mkdir(destination, { recursive: true });
57
+ const entries = await readdir(source, { withFileTypes: true });
58
+
59
+ for (const entry of entries) {
60
+ const sourcePath = path.join(source, entry.name);
61
+ const destinationPath = path.join(destination, entry.name);
62
+
63
+ if (entry.isDirectory()) {
64
+ await copyTree(sourcePath, destinationPath);
65
+ continue;
66
+ }
67
+
68
+ await copyFile(sourcePath, destinationPath);
69
+ }
70
+ }
71
+
72
+ async function writeLaunchScript() {
73
+ const launchScript = `@echo off
74
+ setlocal
75
+ cd /d "%~dp0"
76
+ node dist\\main.js
77
+ `;
78
+ await writeFile(path.join(stagingRoot, "launch-agent-portal.bat"), launchScript, "utf8");
79
+ }
80
+
81
+ async function writeReleaseNotes() {
82
+ const desktopPackageJson = JSON.parse(
83
+ await readFile(path.join(desktopRoot, "package.json"), "utf8")
84
+ );
85
+ const notes = `# Agent Portal Desktop Runtime Package
86
+
87
+ Version: ${desktopPackageJson.version}
88
+
89
+ Included:
90
+ - desktop runtime build output
91
+ - local workflow fixtures
92
+ - shared branding assets
93
+ - launch-agent-portal.bat helper
94
+
95
+ Usage:
96
+ 1. Ensure Node.js is installed on the target machine.
97
+ 2. Open a terminal in this package directory.
98
+ 3. Run \`launch-agent-portal.bat\`.
99
+ `;
100
+ await writeFile(path.join(stagingRoot, "RELEASE_NOTES.md"), notes, "utf8");
101
+ }
102
+
103
+ async function zipWithPowerShell(sourceDirectory, destinationZip) {
104
+ await mkdir(path.dirname(destinationZip), { recursive: true });
105
+ const command = [
106
+ "-NoProfile",
107
+ "-Command",
108
+ `Compress-Archive -Path '${sourceDirectory}\\*' -DestinationPath '${destinationZip}' -Force`
109
+ ];
110
+ await execFileAsync("powershell", command, { cwd: repoRoot });
111
+ }
112
+
113
+ main().catch((error) => {
114
+ console.error("Desktop release packaging failed.");
115
+ console.error(error);
116
+ process.exitCode = 1;
117
+ });
@@ -0,0 +1,46 @@
1
+ from __future__ import annotations
2
+
3
+ import shutil
4
+ import subprocess
5
+ import sys
6
+ from pathlib import Path
7
+
8
+
9
+ REPO_ROOT = Path(__file__).resolve().parents[1]
10
+ PYTHON_PROJECT = REPO_ROOT / "python"
11
+ OUTPUT_DIR = REPO_ROOT / "releases" / "python"
12
+
13
+
14
+ def main() -> int:
15
+ if shutil.which(sys.executable) is None:
16
+ print("Python executable could not be resolved for release packaging.", file=sys.stderr)
17
+ return 1
18
+
19
+ try:
20
+ import build # noqa: F401
21
+ except Exception:
22
+ print(
23
+ "Python release tooling is missing. Install it with `python -m pip install build` "
24
+ "and run `npm run release:python` again.",
25
+ file=sys.stderr,
26
+ )
27
+ return 1
28
+
29
+ OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
30
+
31
+ command = [
32
+ sys.executable,
33
+ "-m",
34
+ "build",
35
+ str(PYTHON_PROJECT),
36
+ "--outdir",
37
+ str(OUTPUT_DIR),
38
+ ]
39
+
40
+ print(f"Building Python artifacts into {OUTPUT_DIR}")
41
+ completed = subprocess.run(command, cwd=REPO_ROOT, check=False)
42
+ return completed.returncode
43
+
44
+
45
+ if __name__ == "__main__":
46
+ raise SystemExit(main())
@@ -0,0 +1,26 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import fs from "node:fs/promises";
4
+ import path from "node:path";
5
+ import { validatePluginManifest } from "../packages/core/dist/index.js";
6
+
7
+ const root = process.cwd();
8
+
9
+ test("plugin manifests validate", async () => {
10
+ const pluginDirs = [
11
+ "agent-portal-vscode",
12
+ "agent-portal-browser",
13
+ "agent-portal-python",
14
+ "agent-portal-skills"
15
+ ];
16
+
17
+ for (const pluginDir of pluginDirs) {
18
+ const raw = await fs.readFile(
19
+ path.join(root, "plugins", pluginDir, "plugin.json"),
20
+ "utf8"
21
+ );
22
+ const manifest = JSON.parse(raw);
23
+ const errors = validatePluginManifest(manifest);
24
+ assert.equal(errors.length, 0, `${pluginDir} manifest failed validation`);
25
+ }
26
+ });
@@ -0,0 +1,41 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import path from "node:path";
4
+ import {
5
+ AgentPortalRuntime,
6
+ BrowserSession,
7
+ createDefaultWorkspace,
8
+ resolveWorkspaceFileUrl
9
+ } from "../packages/core/dist/index.js";
10
+
11
+ const root = process.cwd();
12
+
13
+ test("runtime launches browser, executes workflow, captures report, and shuts down", async () => {
14
+ const workspace = createDefaultWorkspace("test-project");
15
+ const runtime = new AgentPortalRuntime({
16
+ workspace,
17
+ workspaceBasePath: root,
18
+ agents: [{ id: "qa", role: "qa", status: "idle" }]
19
+ });
20
+ const session = new BrowserSession(runtime, {
21
+ headless: true,
22
+ basePath: root
23
+ });
24
+
25
+ await session.launch();
26
+ await session.open(
27
+ resolveWorkspaceFileUrl(root, "apps/desktop/fixtures/local-workflow.html")
28
+ );
29
+ await session.waitForSelector("#name");
30
+ await session.type("#name", "Runtime Test");
31
+ await session.click("#generate-report");
32
+ const text = await session.readText("#result");
33
+ const capture = await session.capture({ label: "runtime-test" });
34
+ const reportPath = await runtime.writeSessionReport();
35
+ await session.shutdownGracefully();
36
+
37
+ assert.match(text.text ?? "", /Runtime Test/);
38
+ assert.equal(capture.snapshot.detectedElements.length > 0, true);
39
+ assert.match(reportPath, /session-/);
40
+ assert.equal(runtime.getOverview().browserStatus, "closed");
41
+ });
@@ -0,0 +1,22 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import fs from "node:fs/promises";
4
+ import path from "node:path";
5
+
6
+ const root = process.cwd();
7
+
8
+ test("VS Code extension package exposes required commands and sidebar", async () => {
9
+ const raw = await fs.readFile(
10
+ path.join(root, "apps", "vscode-extension", "package.json"),
11
+ "utf8"
12
+ );
13
+ const manifest = JSON.parse(raw);
14
+ const commands = manifest.contributes.commands.map((command) => command.command);
15
+
16
+ assert.ok(commands.includes("agentPortal.startRuntime"));
17
+ assert.ok(commands.includes("agentPortal.pauseAgent"));
18
+ assert.ok(commands.includes("agentPortal.resumeAgent"));
19
+ assert.ok(commands.includes("agentPortal.approveNextAction"));
20
+ assert.ok(commands.includes("agentPortal.rejectNextAction"));
21
+ assert.ok(manifest.contributes.views.agentPortal.length > 0);
22
+ });
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "lib": ["ES2022", "DOM"],
7
+ "strict": true,
8
+ "declaration": true,
9
+ "declarationMap": true,
10
+ "sourceMap": true,
11
+ "outDir": "dist",
12
+ "esModuleInterop": true,
13
+ "skipLibCheck": true,
14
+ "forceConsistentCasingInFileNames": true
15
+ }
16
+ }