@elizaos/capacitor-agent 1.0.0 → 2.0.0-beta.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.
@@ -0,0 +1,17 @@
1
+ require 'json'
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = 'ElizaosCapacitorAgent'
7
+ s.version = package['version']
8
+ s.summary = package['description']
9
+ s.license = package['license'] || { :type => 'MIT' }
10
+ s.homepage = 'https://elizaos.ai'
11
+ s.authors = { 'elizaOS' => 'dev@elizaos.ai' }
12
+ s.source = { :git => 'https://github.com/elizaOS/eliza.git', :tag => s.version.to_s }
13
+ s.source_files = 'ios/Sources/**/*.{swift,h,m}'
14
+ s.ios.deployment_target = '13.0'
15
+ s.dependency 'Capacitor'
16
+ s.swift_version = '5.1'
17
+ end
@@ -0,0 +1,30 @@
1
+ ext {
2
+ junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
3
+ androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.6.1'
4
+ }
5
+
6
+ apply plugin: 'com.android.library'
7
+ android {
8
+ namespace = "ai.eliza.plugins.agent"
9
+ compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 34
10
+ defaultConfig {
11
+ minSdk project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22
12
+ targetSdk project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 34
13
+ }
14
+ compileOptions {
15
+ sourceCompatibility JavaVersion.VERSION_17
16
+ targetCompatibility JavaVersion.VERSION_17
17
+ }
18
+ }
19
+
20
+ repositories {
21
+ google()
22
+ maven {
23
+ url = uri(rootProject.ext.has('mavenCentralMirrorUrl') ? rootProject.ext.mavenCentralMirrorUrl : 'https://repo.maven.apache.org/maven2')
24
+ }
25
+ mavenCentral()
26
+ }
27
+
28
+ dependencies {
29
+ implementation project(':capacitor-android')
30
+ }
@@ -0,0 +1 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android" />
@@ -0,0 +1,211 @@
1
+ package ai.eliza.plugins.agent
2
+
3
+ import com.getcapacitor.JSObject
4
+ import com.getcapacitor.Plugin
5
+ import com.getcapacitor.PluginCall
6
+ import com.getcapacitor.PluginMethod
7
+ import com.getcapacitor.annotation.CapacitorPlugin
8
+ import java.io.ByteArrayOutputStream
9
+ import java.net.HttpURLConnection
10
+ import java.net.URL
11
+ import java.util.Locale
12
+ import org.json.JSONObject
13
+
14
+ private const val LOCAL_AGENT_BASE_URL = "http://127.0.0.1:31337"
15
+ private const val MAX_REQUEST_BODY_BYTES = 10 * 1024 * 1024
16
+ private const val MAX_RESPONSE_BODY_BYTES = 10 * 1024 * 1024
17
+
18
+ /**
19
+ * Eliza Agent Plugin — Android bridge.
20
+ *
21
+ * The app module owns ElizaAgentService, so this library uses reflection to
22
+ * avoid a Gradle dependency cycle while still exposing the per-boot loopback
23
+ * bearer token to the WebView.
24
+ */
25
+ @CapacitorPlugin(name = "Agent")
26
+ class AgentPlugin : Plugin() {
27
+ @PluginMethod
28
+ fun start(call: PluginCall) {
29
+ try {
30
+ invokeAgentService("start")
31
+ call.resolve(agentStatus("starting", null))
32
+ } catch (error: Exception) {
33
+ call.reject(error.message ?: "Failed to start local agent")
34
+ }
35
+ }
36
+
37
+ @PluginMethod
38
+ fun stop(call: PluginCall) {
39
+ try {
40
+ invokeAgentService("stop")
41
+ call.resolve(JSObject().apply {
42
+ put("ok", true)
43
+ })
44
+ } catch (error: Exception) {
45
+ call.reject(error.message ?: "Failed to stop local agent")
46
+ }
47
+ }
48
+
49
+ @PluginMethod
50
+ fun getStatus(call: PluginCall) {
51
+ val token = readLocalAgentToken()
52
+ if (token == null) {
53
+ call.resolve(agentStatus("not_started", null))
54
+ return
55
+ }
56
+
57
+ Thread {
58
+ try {
59
+ val result = forwardLocalRequest("/api/status", "GET", JSObject(), null, 1_500, token)
60
+ val json = JSONObject(result.getString("body") ?: "{}")
61
+ call.resolve(agentStatus(
62
+ json.optString("state", "running"),
63
+ json.optString("error").takeIf { it.isNotBlank() },
64
+ ))
65
+ } catch (error: Exception) {
66
+ call.resolve(agentStatus("error", error.message ?: "Local agent status unavailable"))
67
+ }
68
+ }.start()
69
+ }
70
+
71
+ @PluginMethod
72
+ fun getLocalAgentToken(call: PluginCall) {
73
+ val token = readLocalAgentToken()
74
+ call.resolve(JSObject().apply {
75
+ put("available", token != null)
76
+ put("token", token ?: JSONObject.NULL)
77
+ })
78
+ }
79
+
80
+ @PluginMethod
81
+ fun request(call: PluginCall) {
82
+ val path = call.getString("path")?.trim()
83
+ if (path == null || !path.startsWith("/") || path.startsWith("//")) {
84
+ call.reject("Agent.request requires a local path that starts with /")
85
+ return
86
+ }
87
+
88
+ val method = (call.getString("method") ?: "GET").trim().uppercase(Locale.US)
89
+ if (!method.matches(Regex("^[A-Z]{1,16}$"))) {
90
+ call.reject("Unsupported HTTP method")
91
+ return
92
+ }
93
+
94
+ val timeoutMs = (call.getInt("timeoutMs") ?: 10_000).coerceIn(1_000, 120_000)
95
+ val body = call.getString("body")
96
+ val headers = call.getObject("headers") ?: JSObject()
97
+ val token = readLocalAgentToken()
98
+
99
+ Thread {
100
+ try {
101
+ val result = forwardLocalRequest(path, method, headers, body, timeoutMs, token)
102
+ call.resolve(result)
103
+ } catch (error: Exception) {
104
+ call.reject(error.message ?: "Local agent request failed")
105
+ }
106
+ }.start()
107
+ }
108
+
109
+ private fun agentStatus(state: String, error: String?): JSObject {
110
+ return JSObject().apply {
111
+ put("state", state)
112
+ put("agentName", JSONObject.NULL)
113
+ put("port", if (state == "not_started") JSONObject.NULL else 31337)
114
+ put("startedAt", JSONObject.NULL)
115
+ put("error", error ?: JSONObject.NULL)
116
+ }
117
+ }
118
+
119
+ private fun invokeAgentService(methodName: String) {
120
+ val serviceClass = Class.forName("${context.packageName}.ElizaAgentService")
121
+ val method = serviceClass.getMethod(methodName, android.content.Context::class.java)
122
+ method.invoke(null, context)
123
+ }
124
+
125
+ private fun readLocalAgentToken(): String? {
126
+ return try {
127
+ val serviceClass = Class.forName("${context.packageName}.ElizaAgentService")
128
+ val method = serviceClass.getMethod("localAgentToken")
129
+ (method.invoke(null) as? String)?.trim()?.takeIf { it.isNotEmpty() }
130
+ } catch (_: Exception) {
131
+ null
132
+ }
133
+ }
134
+
135
+ private fun forwardLocalRequest(
136
+ path: String,
137
+ method: String,
138
+ headers: JSObject,
139
+ body: String?,
140
+ timeoutMs: Int,
141
+ token: String?,
142
+ ): JSObject {
143
+ val requestBody = body?.toByteArray(Charsets.UTF_8)
144
+ if (requestBody != null && requestBody.size > MAX_REQUEST_BODY_BYTES) {
145
+ throw IllegalArgumentException("Request body is too large")
146
+ }
147
+
148
+ val connection = (URL("$LOCAL_AGENT_BASE_URL$path").openConnection() as HttpURLConnection).apply {
149
+ requestMethod = method
150
+ connectTimeout = timeoutMs
151
+ readTimeout = timeoutMs
152
+ instanceFollowRedirects = false
153
+ useCaches = false
154
+ }
155
+
156
+ for (key in headers.keys()) {
157
+ if (key.equals("host", ignoreCase = true) ||
158
+ key.equals("connection", ignoreCase = true) ||
159
+ key.equals("content-length", ignoreCase = true)
160
+ ) {
161
+ continue
162
+ }
163
+ val value = headers.opt(key) as? String
164
+ if (!value.isNullOrBlank()) {
165
+ connection.setRequestProperty(key, value)
166
+ }
167
+ }
168
+
169
+ if (token != null && connection.getRequestProperty("Authorization").isNullOrBlank()) {
170
+ connection.setRequestProperty("Authorization", "Bearer $token")
171
+ }
172
+
173
+ if (requestBody != null && method != "GET" && method != "HEAD") {
174
+ connection.doOutput = true
175
+ connection.outputStream.use { output ->
176
+ output.write(requestBody)
177
+ }
178
+ }
179
+
180
+ val status = connection.responseCode
181
+ val stream = if (status >= 400) connection.errorStream else connection.inputStream
182
+ val responseBody = stream?.use { input ->
183
+ val output = ByteArrayOutputStream()
184
+ val buffer = ByteArray(8192)
185
+ var total = 0
186
+ while (true) {
187
+ val count = input.read(buffer)
188
+ if (count == -1) break
189
+ total += count
190
+ if (total > MAX_RESPONSE_BODY_BYTES) {
191
+ throw IllegalStateException("Response body is too large")
192
+ }
193
+ output.write(buffer, 0, count)
194
+ }
195
+ output.toString(Charsets.UTF_8.name())
196
+ } ?: ""
197
+
198
+ val responseHeaders = JSObject()
199
+ for ((key, values) in connection.headerFields) {
200
+ if (key == null || values == null || values.isEmpty()) continue
201
+ responseHeaders.put(key.lowercase(Locale.US), values.joinToString(", "))
202
+ }
203
+
204
+ return JSObject().apply {
205
+ put("status", status)
206
+ put("statusText", connection.responseMessage ?: "")
207
+ put("headers", responseHeaders)
208
+ put("body", responseBody)
209
+ }
210
+ }
211
+ }
@@ -18,6 +18,23 @@ export interface ChatResult {
18
18
  text: string;
19
19
  agentName: string;
20
20
  }
21
+ export interface LocalAgentTokenResult {
22
+ available: boolean;
23
+ token: string | null;
24
+ }
25
+ export interface AgentRequestOptions {
26
+ method?: string;
27
+ path: string;
28
+ headers?: Record<string, string>;
29
+ body?: string | null;
30
+ timeoutMs?: number;
31
+ }
32
+ export interface AgentRequestResult {
33
+ status: number;
34
+ statusText: string;
35
+ headers: Record<string, string>;
36
+ body: string;
37
+ }
21
38
  export interface AgentPlugin {
22
39
  /** Start the agent runtime. Resolves when it's ready. */
23
40
  start(): Promise<AgentStatus>;
@@ -31,5 +48,15 @@ export interface AgentPlugin {
31
48
  chat(options: {
32
49
  text: string;
33
50
  }): Promise<ChatResult>;
51
+ /** Read the per-boot bearer token for the bundled Android local agent. */
52
+ getLocalAgentToken?(): Promise<LocalAgentTokenResult>;
53
+ /**
54
+ * Path-only request bridge for the bundled local agent.
55
+ *
56
+ * Native implementations must reject absolute URLs and route only to the
57
+ * app-owned local backend. This is a transitional transport before the
58
+ * backend route kernel can run over Binder/LocalSocket/WKURLSchemeHandler.
59
+ */
60
+ request?(options: AgentRequestOptions): Promise<AgentRequestResult>;
34
61
  }
35
62
  //# sourceMappingURL=definitions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,aAAa,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;IACpE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,yDAAyD;IACzD,KAAK,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC;IAE9B,8BAA8B;IAC9B,IAAI,IAAI,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAEjC,gCAAgC;IAChC,SAAS,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC;IAElC,gDAAgD;IAChD,IAAI,CAAC,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CACtD"}
1
+ {"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,aAAa,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;IACpE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,yDAAyD;IACzD,KAAK,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC;IAE9B,8BAA8B;IAC9B,IAAI,IAAI,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAEjC,gCAAgC;IAChC,SAAS,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC;IAElC,gDAAgD;IAChD,IAAI,CAAC,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAErD,0EAA0E;IAC1E,kBAAkB,CAAC,IAAI,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAEtD;;;;;;OAMG;IACH,OAAO,CAAC,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACrE"}
package/dist/esm/web.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { WebPlugin } from "@capacitor/core";
2
- import type { AgentPlugin, AgentStatus, ChatResult } from "./definitions";
2
+ import type { AgentPlugin, AgentRequestOptions, AgentRequestResult, AgentStatus, ChatResult, LocalAgentTokenResult } from "./definitions";
3
3
  /**
4
4
  * Web fallback implementation.
5
5
  *
@@ -39,5 +39,7 @@ export declare class AgentWeb extends WebPlugin implements AgentPlugin {
39
39
  chat(options: {
40
40
  text: string;
41
41
  }): Promise<ChatResult>;
42
+ getLocalAgentToken(): Promise<LocalAgentTokenResult>;
43
+ request(options: AgentRequestOptions): Promise<AgentRequestResult>;
42
44
  }
43
45
  //# sourceMappingURL=web.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAO1E;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,QAAS,SAAQ,SAAU,YAAW,WAAW;IAC5D,OAAO,CAAC,4BAA4B;IAOpC,OAAO,CAAC,wBAAwB;IAQhC,OAAO,CAAC,yBAAyB;YAUnB,0BAA0B;YA0B1B,mBAAmB;IA6BjC,OAAO,CAAC,OAAO;IAUf,OAAO,CAAC,QAAQ;IAWhB,OAAO,CAAC,WAAW;IAKnB,+CAA+C;IAC/C,OAAO,CAAC,WAAW;IAYb,KAAK,IAAI,OAAO,CAAC,WAAW,CAAC;IAkB7B,IAAI,IAAI,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAA;KAAE,CAAC;IAWhC,SAAS,IAAI,OAAO,CAAC,WAAW,CAAC;IAgBjC,IAAI,CAAC,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,CAAC;CAM3D"}
1
+ {"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,EACV,WAAW,EACX,mBAAmB,EACnB,kBAAkB,EAClB,WAAW,EACX,UAAU,EACV,qBAAqB,EACtB,MAAM,eAAe,CAAC;AAOvB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,QAAS,SAAQ,SAAU,YAAW,WAAW;IAC5D,OAAO,CAAC,4BAA4B;IAOpC,OAAO,CAAC,wBAAwB;IAQhC,OAAO,CAAC,yBAAyB;YAUnB,0BAA0B;YA0B1B,mBAAmB;IA8BjC,OAAO,CAAC,OAAO;IAUf,OAAO,CAAC,QAAQ;IAWhB,OAAO,CAAC,WAAW;IAKnB,+CAA+C;IAC/C,OAAO,CAAC,WAAW;IAYb,KAAK,IAAI,OAAO,CAAC,WAAW,CAAC;IAkB7B,IAAI,IAAI,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAA;KAAE,CAAC;IAWhC,SAAS,IAAI,OAAO,CAAC,WAAW,CAAC;IAgBjC,IAAI,CAAC,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,CAAC;IAOpD,kBAAkB,IAAI,OAAO,CAAC,qBAAqB,CAAC;IAQpD,OAAO,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC;CAuBzE"}
package/dist/esm/web.js CHANGED
@@ -66,6 +66,7 @@ export class AgentWeb extends WebPlugin {
66
66
  }
67
67
  async chatViaConversation(text, retryOnMissingConversation = true) {
68
68
  const conversationId = await this.ensureLegacyConversationId();
69
+ // @duplicate-component-audit-allow: agent API message POST; server-side runtime owns model trajectory logging.
69
70
  const res = await fetch(`${this.apiBase()}/api/conversations/${encodeURIComponent(conversationId)}/messages`, {
70
71
  method: "POST",
71
72
  headers: {
@@ -168,5 +169,35 @@ export class AgentWeb extends WebPlugin {
168
169
  }
169
170
  return this.chatViaConversation(options.text);
170
171
  }
172
+ async getLocalAgentToken() {
173
+ const token = this.apiToken();
174
+ return {
175
+ available: Boolean(token),
176
+ token,
177
+ };
178
+ }
179
+ async request(options) {
180
+ if (!options.path?.startsWith("/")) {
181
+ throw new Error("Agent.request path must start with /");
182
+ }
183
+ const res = await fetch(`${this.apiBase()}${options.path}`, {
184
+ method: options.method ?? "GET",
185
+ headers: {
186
+ ...this.authHeaders(),
187
+ ...options.headers,
188
+ },
189
+ body: options.body ?? undefined,
190
+ });
191
+ const headers = {};
192
+ res.headers.forEach((value, key) => {
193
+ headers[key] = value;
194
+ });
195
+ return {
196
+ status: res.status,
197
+ statusText: res.statusText,
198
+ headers,
199
+ body: await res.text(),
200
+ };
201
+ }
171
202
  }
172
203
  //# sourceMappingURL=web.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"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"}
@@ -75,6 +75,7 @@ class AgentWeb extends core.WebPlugin {
75
75
  }
76
76
  async chatViaConversation(text, retryOnMissingConversation = true) {
77
77
  const conversationId = await this.ensureLegacyConversationId();
78
+ // @duplicate-component-audit-allow: agent API message POST; server-side runtime owns model trajectory logging.
78
79
  const res = await fetch(`${this.apiBase()}/api/conversations/${encodeURIComponent(conversationId)}/messages`, {
79
80
  method: "POST",
80
81
  headers: {
@@ -177,6 +178,36 @@ class AgentWeb extends core.WebPlugin {
177
178
  }
178
179
  return this.chatViaConversation(options.text);
179
180
  }
181
+ async getLocalAgentToken() {
182
+ const token = this.apiToken();
183
+ return {
184
+ available: Boolean(token),
185
+ token,
186
+ };
187
+ }
188
+ async request(options) {
189
+ if (!options.path?.startsWith("/")) {
190
+ throw new Error("Agent.request path must start with /");
191
+ }
192
+ const res = await fetch(`${this.apiBase()}${options.path}`, {
193
+ method: options.method ?? "GET",
194
+ headers: {
195
+ ...this.authHeaders(),
196
+ ...options.headers,
197
+ },
198
+ body: options.body ?? undefined,
199
+ });
200
+ const headers = {};
201
+ res.headers.forEach((value, key) => {
202
+ headers[key] = value;
203
+ });
204
+ return {
205
+ status: res.status,
206
+ statusText: res.statusText,
207
+ headers,
208
+ body: await res.text(),
209
+ };
210
+ }
180
211
  }
181
212
 
182
213
  var web = /*#__PURE__*/Object.freeze({
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from \"@capacitor/core\";\nexport * from \"./definitions\";\nexport const Agent = registerPlugin(\"Agent\", {\n web: () => import(\"./web\").then((m) => new m.AgentWeb()),\n // Electrobun uses the preload bridge (agent:start, agent:stop, etc.)\n // iOS/Android will use the web fallback (HTTP to API server) for now\n});\n//# sourceMappingURL=index.js.map","import { WebPlugin } from \"@capacitor/core\";\n/**\n * Web fallback implementation.\n *\n * On non-desktop platforms (iOS, Android, web), the agent runtime runs\n * on a server. This implementation delegates to the HTTP API.\n *\n * In Electrobun the desktop bridge calls the native main-process\n * implementation via RPC instead — this web fallback is only used when\n * no native plugin is available. If the page is served from a non-HTTP\n * origin (e.g. electrobun://), relative fetches would hit the\n * app shell HTML, so we bail early.\n *\n * Local-agent-on-Android (Phase E): when the host UI selects the\n * \"Local Agent\" tile, it sets `apiBase` to `http://127.0.0.1:31337`,\n * which the runtime mirrors into `window.__ELIZA_API_BASE__`. From this\n * plugin's perspective there is no special case — it simply HTTP-POSTs\n * to `${apiBase}/api/agent/start|stop|status`, which is exactly the same\n * surface Phase B's `ElizaAgentService` exposes. The web fallback path\n * therefore works unchanged for both remote and on-device agents.\n */\nexport class AgentWeb extends WebPlugin {\n legacyConversationStorageKey() {\n const base = this.apiBase() ||\n (typeof window !== \"undefined\" ? window.location.origin : \"same-origin\");\n return `eliza_agent_web_conversation:${encodeURIComponent(base)}`;\n }\n readLegacyConversationId() {\n if (typeof window === \"undefined\")\n return null;\n const stored = window.sessionStorage.getItem(this.legacyConversationStorageKey());\n return stored?.trim() ? stored.trim() : null;\n }\n writeLegacyConversationId(conversationId) {\n if (typeof window === \"undefined\")\n return;\n const key = this.legacyConversationStorageKey();\n if (conversationId?.trim()) {\n window.sessionStorage.setItem(key, conversationId.trim());\n return;\n }\n window.sessionStorage.removeItem(key);\n }\n async ensureLegacyConversationId() {\n const cached = this.readLegacyConversationId();\n if (cached)\n return cached;\n const res = await fetch(`${this.apiBase()}/api/conversations`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...this.authHeaders(),\n },\n body: JSON.stringify({ title: \"Quick Chat\" }),\n });\n if (!res.ok) {\n throw new Error(`Failed to create conversation: ${res.status}`);\n }\n const data = (await res.json());\n const conversationId = data.conversation?.id?.trim();\n if (!conversationId) {\n throw new Error(\"Conversation create response missing id\");\n }\n this.writeLegacyConversationId(conversationId);\n return conversationId;\n }\n async chatViaConversation(text, retryOnMissingConversation = true) {\n const conversationId = await this.ensureLegacyConversationId();\n const res = await fetch(`${this.apiBase()}/api/conversations/${encodeURIComponent(conversationId)}/messages`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...this.authHeaders(),\n },\n body: JSON.stringify({ text, channelType: \"DM\" }),\n });\n if (res.status === 404 && retryOnMissingConversation) {\n this.writeLegacyConversationId(null);\n return this.chatViaConversation(text, false);\n }\n if (!res.ok) {\n throw new Error(`Chat request failed: ${res.status}`);\n }\n return res.json();\n }\n apiBase() {\n const global = typeof window !== \"undefined\"\n ? window.__ELIZA_API_BASE__\n : undefined;\n if (typeof global === \"string\" && global.trim().length > 0)\n return global;\n // No explicit base — use relative URLs (works on http/https origins).\n return \"\";\n }\n apiToken() {\n const global = typeof window !== \"undefined\"\n ? window.__ELIZA_API_TOKEN__\n : undefined;\n if (typeof global === \"string\" && global.trim())\n return global.trim();\n if (typeof window === \"undefined\")\n return null;\n const stored = window.sessionStorage.getItem(\"eliza_api_token\");\n return stored?.trim() ? stored.trim() : null;\n }\n authHeaders() {\n const token = this.apiToken();\n return token ? { Authorization: `Bearer ${token}` } : {};\n }\n /** True when we can reach the API via HTTP. */\n canReachApi() {\n const global = typeof window !== \"undefined\"\n ? window.__ELIZA_API_BASE__\n : undefined;\n if (typeof global === \"string\" && global.trim().length > 0)\n return true;\n // No explicit base — relative fetches only work on http(s) origins.\n if (typeof window === \"undefined\")\n return false;\n const proto = window.location.protocol;\n return proto === \"http:\" || proto === \"https:\";\n }\n async start() {\n if (!this.canReachApi()) {\n return {\n state: \"not_started\",\n agentName: null,\n port: null,\n startedAt: null,\n error: \"No API endpoint\",\n };\n }\n const res = await fetch(`${this.apiBase()}/api/agent/start`, {\n method: \"POST\",\n headers: this.authHeaders(),\n });\n const data = await res.json();\n return data.status ?? data;\n }\n async stop() {\n if (!this.canReachApi()) {\n return { ok: false };\n }\n const res = await fetch(`${this.apiBase()}/api/agent/stop`, {\n method: \"POST\",\n headers: this.authHeaders(),\n });\n return res.json();\n }\n async getStatus() {\n if (!this.canReachApi()) {\n return {\n state: \"not_started\",\n agentName: null,\n port: null,\n startedAt: null,\n error: \"No API endpoint\",\n };\n }\n const res = await fetch(`${this.apiBase()}/api/status`, {\n headers: this.authHeaders(),\n });\n return res.json();\n }\n async chat(options) {\n if (!this.canReachApi()) {\n return { text: \"Agent API not available\", agentName: \"System\" };\n }\n return this.chatViaConversation(options.text);\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":"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"}
1
+ {"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from \"@capacitor/core\";\nexport * from \"./definitions\";\nexport const Agent = registerPlugin(\"Agent\", {\n web: () => import(\"./web\").then((m) => new m.AgentWeb()),\n // Electrobun uses the preload bridge (agent:start, agent:stop, etc.)\n // iOS/Android will use the web fallback (HTTP to API server) for now\n});\n//# sourceMappingURL=index.js.map","import { WebPlugin } from \"@capacitor/core\";\n/**\n * Web fallback implementation.\n *\n * On non-desktop platforms (iOS, Android, web), the agent runtime runs\n * on a server. This implementation delegates to the HTTP API.\n *\n * In Electrobun the desktop bridge calls the native main-process\n * implementation via RPC instead — this web fallback is only used when\n * no native plugin is available. If the page is served from a non-HTTP\n * origin (e.g. electrobun://), relative fetches would hit the\n * app shell HTML, so we bail early.\n *\n * Local-agent-on-Android (Phase E): when the host UI selects the\n * \"Local Agent\" tile, it sets `apiBase` to `http://127.0.0.1:31337`,\n * which the runtime mirrors into `window.__ELIZA_API_BASE__`. From this\n * plugin's perspective there is no special case — it simply HTTP-POSTs\n * to `${apiBase}/api/agent/start|stop|status`, which is exactly the same\n * surface Phase B's `ElizaAgentService` exposes. The web fallback path\n * therefore works unchanged for both remote and on-device agents.\n */\nexport class AgentWeb extends WebPlugin {\n legacyConversationStorageKey() {\n const base = this.apiBase() ||\n (typeof window !== \"undefined\" ? window.location.origin : \"same-origin\");\n return `eliza_agent_web_conversation:${encodeURIComponent(base)}`;\n }\n readLegacyConversationId() {\n if (typeof window === \"undefined\")\n return null;\n const stored = window.sessionStorage.getItem(this.legacyConversationStorageKey());\n return stored?.trim() ? stored.trim() : null;\n }\n writeLegacyConversationId(conversationId) {\n if (typeof window === \"undefined\")\n return;\n const key = this.legacyConversationStorageKey();\n if (conversationId?.trim()) {\n window.sessionStorage.setItem(key, conversationId.trim());\n return;\n }\n window.sessionStorage.removeItem(key);\n }\n async ensureLegacyConversationId() {\n const cached = this.readLegacyConversationId();\n if (cached)\n return cached;\n const res = await fetch(`${this.apiBase()}/api/conversations`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...this.authHeaders(),\n },\n body: JSON.stringify({ title: \"Quick Chat\" }),\n });\n if (!res.ok) {\n throw new Error(`Failed to create conversation: ${res.status}`);\n }\n const data = (await res.json());\n const conversationId = data.conversation?.id?.trim();\n if (!conversationId) {\n throw new Error(\"Conversation create response missing id\");\n }\n this.writeLegacyConversationId(conversationId);\n return conversationId;\n }\n async chatViaConversation(text, retryOnMissingConversation = true) {\n const conversationId = await this.ensureLegacyConversationId();\n // @duplicate-component-audit-allow: agent API message POST; server-side runtime owns model trajectory logging.\n const res = await fetch(`${this.apiBase()}/api/conversations/${encodeURIComponent(conversationId)}/messages`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...this.authHeaders(),\n },\n body: JSON.stringify({ text, channelType: \"DM\" }),\n });\n if (res.status === 404 && retryOnMissingConversation) {\n this.writeLegacyConversationId(null);\n return this.chatViaConversation(text, false);\n }\n if (!res.ok) {\n throw new Error(`Chat request failed: ${res.status}`);\n }\n return res.json();\n }\n apiBase() {\n const global = typeof window !== \"undefined\"\n ? window.__ELIZA_API_BASE__\n : undefined;\n if (typeof global === \"string\" && global.trim().length > 0)\n return global;\n // No explicit base — use relative URLs (works on http/https origins).\n return \"\";\n }\n apiToken() {\n const global = typeof window !== \"undefined\"\n ? window.__ELIZA_API_TOKEN__\n : undefined;\n if (typeof global === \"string\" && global.trim())\n return global.trim();\n if (typeof window === \"undefined\")\n return null;\n const stored = window.sessionStorage.getItem(\"eliza_api_token\");\n return stored?.trim() ? stored.trim() : null;\n }\n authHeaders() {\n const token = this.apiToken();\n return token ? { Authorization: `Bearer ${token}` } : {};\n }\n /** True when we can reach the API via HTTP. */\n canReachApi() {\n const global = typeof window !== \"undefined\"\n ? window.__ELIZA_API_BASE__\n : undefined;\n if (typeof global === \"string\" && global.trim().length > 0)\n return true;\n // No explicit base — relative fetches only work on http(s) origins.\n if (typeof window === \"undefined\")\n return false;\n const proto = window.location.protocol;\n return proto === \"http:\" || proto === \"https:\";\n }\n async start() {\n if (!this.canReachApi()) {\n return {\n state: \"not_started\",\n agentName: null,\n port: null,\n startedAt: null,\n error: \"No API endpoint\",\n };\n }\n const res = await fetch(`${this.apiBase()}/api/agent/start`, {\n method: \"POST\",\n headers: this.authHeaders(),\n });\n const data = await res.json();\n return data.status ?? data;\n }\n async stop() {\n if (!this.canReachApi()) {\n return { ok: false };\n }\n const res = await fetch(`${this.apiBase()}/api/agent/stop`, {\n method: \"POST\",\n headers: this.authHeaders(),\n });\n return res.json();\n }\n async getStatus() {\n if (!this.canReachApi()) {\n return {\n state: \"not_started\",\n agentName: null,\n port: null,\n startedAt: null,\n error: \"No API endpoint\",\n };\n }\n const res = await fetch(`${this.apiBase()}/api/status`, {\n headers: this.authHeaders(),\n });\n return res.json();\n }\n async chat(options) {\n if (!this.canReachApi()) {\n return { text: \"Agent API not available\", agentName: \"System\" };\n }\n return this.chatViaConversation(options.text);\n }\n async getLocalAgentToken() {\n const token = this.apiToken();\n return {\n available: Boolean(token),\n token,\n };\n }\n async request(options) {\n if (!options.path?.startsWith(\"/\")) {\n throw new Error(\"Agent.request path must start with /\");\n }\n const res = await fetch(`${this.apiBase()}${options.path}`, {\n method: options.method ?? \"GET\",\n headers: {\n ...this.authHeaders(),\n ...options.headers,\n },\n body: options.body ?? undefined,\n });\n const headers = {};\n res.headers.forEach((value, key) => {\n headers[key] = value;\n });\n return {\n status: res.status,\n statusText: res.statusText,\n headers,\n body: await res.text(),\n };\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":"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"}
package/dist/plugin.js CHANGED
@@ -74,6 +74,7 @@ var capacitorAgent = (function (exports, core) {
74
74
  }
75
75
  async chatViaConversation(text, retryOnMissingConversation = true) {
76
76
  const conversationId = await this.ensureLegacyConversationId();
77
+ // @duplicate-component-audit-allow: agent API message POST; server-side runtime owns model trajectory logging.
77
78
  const res = await fetch(`${this.apiBase()}/api/conversations/${encodeURIComponent(conversationId)}/messages`, {
78
79
  method: "POST",
79
80
  headers: {
@@ -176,6 +177,36 @@ var capacitorAgent = (function (exports, core) {
176
177
  }
177
178
  return this.chatViaConversation(options.text);
178
179
  }
180
+ async getLocalAgentToken() {
181
+ const token = this.apiToken();
182
+ return {
183
+ available: Boolean(token),
184
+ token,
185
+ };
186
+ }
187
+ async request(options) {
188
+ if (!options.path?.startsWith("/")) {
189
+ throw new Error("Agent.request path must start with /");
190
+ }
191
+ const res = await fetch(`${this.apiBase()}${options.path}`, {
192
+ method: options.method ?? "GET",
193
+ headers: {
194
+ ...this.authHeaders(),
195
+ ...options.headers,
196
+ },
197
+ body: options.body ?? undefined,
198
+ });
199
+ const headers = {};
200
+ res.headers.forEach((value, key) => {
201
+ headers[key] = value;
202
+ });
203
+ return {
204
+ status: res.status,
205
+ statusText: res.statusText,
206
+ headers,
207
+ body: await res.text(),
208
+ };
209
+ }
179
210
  }
180
211
 
181
212
  var web = /*#__PURE__*/Object.freeze({
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from \"@capacitor/core\";\nexport * from \"./definitions\";\nexport const Agent = registerPlugin(\"Agent\", {\n web: () => import(\"./web\").then((m) => new m.AgentWeb()),\n // Electrobun uses the preload bridge (agent:start, agent:stop, etc.)\n // iOS/Android will use the web fallback (HTTP to API server) for now\n});\n//# sourceMappingURL=index.js.map","import { WebPlugin } from \"@capacitor/core\";\n/**\n * Web fallback implementation.\n *\n * On non-desktop platforms (iOS, Android, web), the agent runtime runs\n * on a server. This implementation delegates to the HTTP API.\n *\n * In Electrobun the desktop bridge calls the native main-process\n * implementation via RPC instead — this web fallback is only used when\n * no native plugin is available. If the page is served from a non-HTTP\n * origin (e.g. electrobun://), relative fetches would hit the\n * app shell HTML, so we bail early.\n *\n * Local-agent-on-Android (Phase E): when the host UI selects the\n * \"Local Agent\" tile, it sets `apiBase` to `http://127.0.0.1:31337`,\n * which the runtime mirrors into `window.__ELIZA_API_BASE__`. From this\n * plugin's perspective there is no special case — it simply HTTP-POSTs\n * to `${apiBase}/api/agent/start|stop|status`, which is exactly the same\n * surface Phase B's `ElizaAgentService` exposes. The web fallback path\n * therefore works unchanged for both remote and on-device agents.\n */\nexport class AgentWeb extends WebPlugin {\n legacyConversationStorageKey() {\n const base = this.apiBase() ||\n (typeof window !== \"undefined\" ? window.location.origin : \"same-origin\");\n return `eliza_agent_web_conversation:${encodeURIComponent(base)}`;\n }\n readLegacyConversationId() {\n if (typeof window === \"undefined\")\n return null;\n const stored = window.sessionStorage.getItem(this.legacyConversationStorageKey());\n return stored?.trim() ? stored.trim() : null;\n }\n writeLegacyConversationId(conversationId) {\n if (typeof window === \"undefined\")\n return;\n const key = this.legacyConversationStorageKey();\n if (conversationId?.trim()) {\n window.sessionStorage.setItem(key, conversationId.trim());\n return;\n }\n window.sessionStorage.removeItem(key);\n }\n async ensureLegacyConversationId() {\n const cached = this.readLegacyConversationId();\n if (cached)\n return cached;\n const res = await fetch(`${this.apiBase()}/api/conversations`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...this.authHeaders(),\n },\n body: JSON.stringify({ title: \"Quick Chat\" }),\n });\n if (!res.ok) {\n throw new Error(`Failed to create conversation: ${res.status}`);\n }\n const data = (await res.json());\n const conversationId = data.conversation?.id?.trim();\n if (!conversationId) {\n throw new Error(\"Conversation create response missing id\");\n }\n this.writeLegacyConversationId(conversationId);\n return conversationId;\n }\n async chatViaConversation(text, retryOnMissingConversation = true) {\n const conversationId = await this.ensureLegacyConversationId();\n const res = await fetch(`${this.apiBase()}/api/conversations/${encodeURIComponent(conversationId)}/messages`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...this.authHeaders(),\n },\n body: JSON.stringify({ text, channelType: \"DM\" }),\n });\n if (res.status === 404 && retryOnMissingConversation) {\n this.writeLegacyConversationId(null);\n return this.chatViaConversation(text, false);\n }\n if (!res.ok) {\n throw new Error(`Chat request failed: ${res.status}`);\n }\n return res.json();\n }\n apiBase() {\n const global = typeof window !== \"undefined\"\n ? window.__ELIZA_API_BASE__\n : undefined;\n if (typeof global === \"string\" && global.trim().length > 0)\n return global;\n // No explicit base — use relative URLs (works on http/https origins).\n return \"\";\n }\n apiToken() {\n const global = typeof window !== \"undefined\"\n ? window.__ELIZA_API_TOKEN__\n : undefined;\n if (typeof global === \"string\" && global.trim())\n return global.trim();\n if (typeof window === \"undefined\")\n return null;\n const stored = window.sessionStorage.getItem(\"eliza_api_token\");\n return stored?.trim() ? stored.trim() : null;\n }\n authHeaders() {\n const token = this.apiToken();\n return token ? { Authorization: `Bearer ${token}` } : {};\n }\n /** True when we can reach the API via HTTP. */\n canReachApi() {\n const global = typeof window !== \"undefined\"\n ? window.__ELIZA_API_BASE__\n : undefined;\n if (typeof global === \"string\" && global.trim().length > 0)\n return true;\n // No explicit base — relative fetches only work on http(s) origins.\n if (typeof window === \"undefined\")\n return false;\n const proto = window.location.protocol;\n return proto === \"http:\" || proto === \"https:\";\n }\n async start() {\n if (!this.canReachApi()) {\n return {\n state: \"not_started\",\n agentName: null,\n port: null,\n startedAt: null,\n error: \"No API endpoint\",\n };\n }\n const res = await fetch(`${this.apiBase()}/api/agent/start`, {\n method: \"POST\",\n headers: this.authHeaders(),\n });\n const data = await res.json();\n return data.status ?? data;\n }\n async stop() {\n if (!this.canReachApi()) {\n return { ok: false };\n }\n const res = await fetch(`${this.apiBase()}/api/agent/stop`, {\n method: \"POST\",\n headers: this.authHeaders(),\n });\n return res.json();\n }\n async getStatus() {\n if (!this.canReachApi()) {\n return {\n state: \"not_started\",\n agentName: null,\n port: null,\n startedAt: null,\n error: \"No API endpoint\",\n };\n }\n const res = await fetch(`${this.apiBase()}/api/status`, {\n headers: this.authHeaders(),\n });\n return res.json();\n }\n async chat(options) {\n if (!this.canReachApi()) {\n return { text: \"Agent API not available\", agentName: \"System\" };\n }\n return this.chatViaConversation(options.text);\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":"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"}
1
+ {"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from \"@capacitor/core\";\nexport * from \"./definitions\";\nexport const Agent = registerPlugin(\"Agent\", {\n web: () => import(\"./web\").then((m) => new m.AgentWeb()),\n // Electrobun uses the preload bridge (agent:start, agent:stop, etc.)\n // iOS/Android will use the web fallback (HTTP to API server) for now\n});\n//# sourceMappingURL=index.js.map","import { WebPlugin } from \"@capacitor/core\";\n/**\n * Web fallback implementation.\n *\n * On non-desktop platforms (iOS, Android, web), the agent runtime runs\n * on a server. This implementation delegates to the HTTP API.\n *\n * In Electrobun the desktop bridge calls the native main-process\n * implementation via RPC instead — this web fallback is only used when\n * no native plugin is available. If the page is served from a non-HTTP\n * origin (e.g. electrobun://), relative fetches would hit the\n * app shell HTML, so we bail early.\n *\n * Local-agent-on-Android (Phase E): when the host UI selects the\n * \"Local Agent\" tile, it sets `apiBase` to `http://127.0.0.1:31337`,\n * which the runtime mirrors into `window.__ELIZA_API_BASE__`. From this\n * plugin's perspective there is no special case — it simply HTTP-POSTs\n * to `${apiBase}/api/agent/start|stop|status`, which is exactly the same\n * surface Phase B's `ElizaAgentService` exposes. The web fallback path\n * therefore works unchanged for both remote and on-device agents.\n */\nexport class AgentWeb extends WebPlugin {\n legacyConversationStorageKey() {\n const base = this.apiBase() ||\n (typeof window !== \"undefined\" ? window.location.origin : \"same-origin\");\n return `eliza_agent_web_conversation:${encodeURIComponent(base)}`;\n }\n readLegacyConversationId() {\n if (typeof window === \"undefined\")\n return null;\n const stored = window.sessionStorage.getItem(this.legacyConversationStorageKey());\n return stored?.trim() ? stored.trim() : null;\n }\n writeLegacyConversationId(conversationId) {\n if (typeof window === \"undefined\")\n return;\n const key = this.legacyConversationStorageKey();\n if (conversationId?.trim()) {\n window.sessionStorage.setItem(key, conversationId.trim());\n return;\n }\n window.sessionStorage.removeItem(key);\n }\n async ensureLegacyConversationId() {\n const cached = this.readLegacyConversationId();\n if (cached)\n return cached;\n const res = await fetch(`${this.apiBase()}/api/conversations`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...this.authHeaders(),\n },\n body: JSON.stringify({ title: \"Quick Chat\" }),\n });\n if (!res.ok) {\n throw new Error(`Failed to create conversation: ${res.status}`);\n }\n const data = (await res.json());\n const conversationId = data.conversation?.id?.trim();\n if (!conversationId) {\n throw new Error(\"Conversation create response missing id\");\n }\n this.writeLegacyConversationId(conversationId);\n return conversationId;\n }\n async chatViaConversation(text, retryOnMissingConversation = true) {\n const conversationId = await this.ensureLegacyConversationId();\n // @duplicate-component-audit-allow: agent API message POST; server-side runtime owns model trajectory logging.\n const res = await fetch(`${this.apiBase()}/api/conversations/${encodeURIComponent(conversationId)}/messages`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...this.authHeaders(),\n },\n body: JSON.stringify({ text, channelType: \"DM\" }),\n });\n if (res.status === 404 && retryOnMissingConversation) {\n this.writeLegacyConversationId(null);\n return this.chatViaConversation(text, false);\n }\n if (!res.ok) {\n throw new Error(`Chat request failed: ${res.status}`);\n }\n return res.json();\n }\n apiBase() {\n const global = typeof window !== \"undefined\"\n ? window.__ELIZA_API_BASE__\n : undefined;\n if (typeof global === \"string\" && global.trim().length > 0)\n return global;\n // No explicit base — use relative URLs (works on http/https origins).\n return \"\";\n }\n apiToken() {\n const global = typeof window !== \"undefined\"\n ? window.__ELIZA_API_TOKEN__\n : undefined;\n if (typeof global === \"string\" && global.trim())\n return global.trim();\n if (typeof window === \"undefined\")\n return null;\n const stored = window.sessionStorage.getItem(\"eliza_api_token\");\n return stored?.trim() ? stored.trim() : null;\n }\n authHeaders() {\n const token = this.apiToken();\n return token ? { Authorization: `Bearer ${token}` } : {};\n }\n /** True when we can reach the API via HTTP. */\n canReachApi() {\n const global = typeof window !== \"undefined\"\n ? window.__ELIZA_API_BASE__\n : undefined;\n if (typeof global === \"string\" && global.trim().length > 0)\n return true;\n // No explicit base — relative fetches only work on http(s) origins.\n if (typeof window === \"undefined\")\n return false;\n const proto = window.location.protocol;\n return proto === \"http:\" || proto === \"https:\";\n }\n async start() {\n if (!this.canReachApi()) {\n return {\n state: \"not_started\",\n agentName: null,\n port: null,\n startedAt: null,\n error: \"No API endpoint\",\n };\n }\n const res = await fetch(`${this.apiBase()}/api/agent/start`, {\n method: \"POST\",\n headers: this.authHeaders(),\n });\n const data = await res.json();\n return data.status ?? data;\n }\n async stop() {\n if (!this.canReachApi()) {\n return { ok: false };\n }\n const res = await fetch(`${this.apiBase()}/api/agent/stop`, {\n method: \"POST\",\n headers: this.authHeaders(),\n });\n return res.json();\n }\n async getStatus() {\n if (!this.canReachApi()) {\n return {\n state: \"not_started\",\n agentName: null,\n port: null,\n startedAt: null,\n error: \"No API endpoint\",\n };\n }\n const res = await fetch(`${this.apiBase()}/api/status`, {\n headers: this.authHeaders(),\n });\n return res.json();\n }\n async chat(options) {\n if (!this.canReachApi()) {\n return { text: \"Agent API not available\", agentName: \"System\" };\n }\n return this.chatViaConversation(options.text);\n }\n async getLocalAgentToken() {\n const token = this.apiToken();\n return {\n available: Boolean(token),\n token,\n };\n }\n async request(options) {\n if (!options.path?.startsWith(\"/\")) {\n throw new Error(\"Agent.request path must start with /\");\n }\n const res = await fetch(`${this.apiBase()}${options.path}`, {\n method: options.method ?? \"GET\",\n headers: {\n ...this.authHeaders(),\n ...options.headers,\n },\n body: options.body ?? undefined,\n });\n const headers = {};\n res.headers.forEach((value, key) => {\n headers[key] = value;\n });\n return {\n status: res.status,\n statusText: res.statusText,\n headers,\n body: await res.text(),\n };\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":"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"}
@@ -0,0 +1,565 @@
1
+ import Foundation
2
+ import Capacitor
3
+
4
+ private let maxRequestBodyBytes = 10 * 1024 * 1024
5
+ private let maxResponseBodyBytes = 10 * 1024 * 1024
6
+
7
+ private struct AgentEndpoint {
8
+ let baseURL: URL
9
+ let token: String?
10
+ }
11
+
12
+ private struct AgentHTTPResponse {
13
+ let status: Int
14
+ let statusText: String
15
+ let headers: [String: String]
16
+ let body: String
17
+ }
18
+
19
+ /// Eliza Agent Plugin — iOS HTTP bridge.
20
+ ///
21
+ /// iOS does not bundle a Bun runtime. This plugin bridges the Capacitor
22
+ /// Agent API to an explicitly configured HTTP agent endpoint, such as a
23
+ /// local Mac dev server or a remote Eliza agent. Without that endpoint it
24
+ /// fails with an actionable error instead of pretending a local agent exists.
25
+ @objc(AgentPlugin)
26
+ public class AgentPlugin: CAPPlugin, CAPBridgedPlugin {
27
+ public let identifier = "AgentPlugin"
28
+ public let jsName = "Agent"
29
+ public let pluginMethods: [CAPPluginMethod] = [
30
+ CAPPluginMethod(name: "start", returnType: CAPPluginReturnPromise),
31
+ CAPPluginMethod(name: "stop", returnType: CAPPluginReturnPromise),
32
+ CAPPluginMethod(name: "getStatus", returnType: CAPPluginReturnPromise),
33
+ CAPPluginMethod(name: "chat", returnType: CAPPluginReturnPromise),
34
+ CAPPluginMethod(name: "getLocalAgentToken", returnType: CAPPluginReturnPromise),
35
+ CAPPluginMethod(name: "request", returnType: CAPPluginReturnPromise),
36
+ ]
37
+
38
+ private static var conversationIdByBaseURL: [String: String] = [:]
39
+
40
+ @objc func start(_ call: CAPPluginCall) {
41
+ guard let endpoint = resolveEndpoint(call: call) else {
42
+ call.reject(missingEndpointMessage())
43
+ return
44
+ }
45
+
46
+ sendJSON(endpoint: endpoint, path: "/api/agent/start", method: "POST", timeoutMs: timeoutMs(from: call)) { result in
47
+ switch result {
48
+ case .success(let response):
49
+ guard self.isHTTPSuccess(response.status) else {
50
+ call.reject(self.httpErrorMessage(prefix: "Agent start failed", response: response))
51
+ return
52
+ }
53
+ let payload = self.parseJSONObject(response.body)
54
+ let statusPayload = (payload?["status"] as? JSObject) ?? payload ?? [:]
55
+ call.resolve(self.normalizedStatus(statusPayload, fallbackState: "running", endpoint: endpoint, error: nil))
56
+ case .failure(let error):
57
+ call.reject("Agent start failed: \(error.localizedDescription)")
58
+ }
59
+ }
60
+ }
61
+
62
+ @objc func stop(_ call: CAPPluginCall) {
63
+ guard let endpoint = resolveEndpoint(call: call) else {
64
+ call.reject(missingEndpointMessage())
65
+ return
66
+ }
67
+
68
+ sendJSON(endpoint: endpoint, path: "/api/agent/stop", method: "POST", timeoutMs: timeoutMs(from: call)) { result in
69
+ switch result {
70
+ case .success(let response):
71
+ guard self.isHTTPSuccess(response.status) else {
72
+ call.reject(self.httpErrorMessage(prefix: "Agent stop failed", response: response))
73
+ return
74
+ }
75
+ let payload = self.parseJSONObject(response.body)
76
+ let ok = (payload?["ok"] as? Bool) ?? true
77
+ call.resolve(["ok": ok])
78
+ case .failure(let error):
79
+ call.reject("Agent stop failed: \(error.localizedDescription)")
80
+ }
81
+ }
82
+ }
83
+
84
+ @objc func getStatus(_ call: CAPPluginCall) {
85
+ guard let endpoint = resolveEndpoint(call: call) else {
86
+ call.resolve(status(state: "error", agentName: nil, port: nil, startedAt: nil, error: missingEndpointMessage()))
87
+ return
88
+ }
89
+
90
+ sendJSON(endpoint: endpoint, path: "/api/status", method: "GET", timeoutMs: timeoutMs(from: call, defaultValue: 1_500)) { result in
91
+ switch result {
92
+ case .success(let response):
93
+ guard self.isHTTPSuccess(response.status) else {
94
+ call.resolve(self.status(
95
+ state: "error",
96
+ agentName: nil,
97
+ port: self.port(from: endpoint.baseURL),
98
+ startedAt: nil,
99
+ error: self.httpErrorMessage(prefix: "Agent status unavailable", response: response)
100
+ ))
101
+ return
102
+ }
103
+ let payload = self.parseJSONObject(response.body) ?? [:]
104
+ call.resolve(self.normalizedStatus(payload, fallbackState: "running", endpoint: endpoint, error: nil))
105
+ case .failure(let error):
106
+ call.resolve(self.status(
107
+ state: "error",
108
+ agentName: nil,
109
+ port: self.port(from: endpoint.baseURL),
110
+ startedAt: nil,
111
+ error: "Agent status unavailable: \(error.localizedDescription)"
112
+ ))
113
+ }
114
+ }
115
+ }
116
+
117
+ @objc func chat(_ call: CAPPluginCall) {
118
+ guard let text = call.getString("text")?.trimmingCharacters(in: .whitespacesAndNewlines), !text.isEmpty else {
119
+ call.reject("Agent.chat requires non-empty text")
120
+ return
121
+ }
122
+ guard let endpoint = resolveEndpoint(call: call) else {
123
+ call.reject(missingEndpointMessage())
124
+ return
125
+ }
126
+
127
+ ensureConversation(endpoint: endpoint, timeoutMs: timeoutMs(from: call)) { conversationResult in
128
+ switch conversationResult {
129
+ case .success(let conversationId):
130
+ self.sendChatMessage(endpoint: endpoint, conversationId: conversationId, text: text, timeoutMs: self.timeoutMs(from: call), retryOnMissingConversation: true) { result in
131
+ switch result {
132
+ case .success(let payload):
133
+ call.resolve(payload)
134
+ case .failure(let error):
135
+ call.reject(error.localizedDescription)
136
+ }
137
+ }
138
+ case .failure(let error):
139
+ call.reject(error.localizedDescription)
140
+ }
141
+ }
142
+ }
143
+
144
+ @objc func getLocalAgentToken(_ call: CAPPluginCall) {
145
+ let token = resolveEndpoint(call: call)?.token
146
+ call.resolve([
147
+ "available": token != nil,
148
+ "token": token ?? NSNull(),
149
+ ])
150
+ }
151
+
152
+ @objc func request(_ call: CAPPluginCall) {
153
+ guard let endpoint = resolveEndpoint(call: call) else {
154
+ call.reject(missingEndpointMessage())
155
+ return
156
+ }
157
+ guard let path = call.getString("path")?.trimmingCharacters(in: .whitespacesAndNewlines),
158
+ isSafeLocalPath(path) else {
159
+ call.reject("Agent.request requires a local path that starts with / and is not an absolute URL")
160
+ return
161
+ }
162
+ let method = (call.getString("method") ?? "GET").trimmingCharacters(in: .whitespacesAndNewlines).uppercased()
163
+ guard method.range(of: "^[A-Z]{1,16}$", options: .regularExpression) != nil else {
164
+ call.reject("Unsupported HTTP method")
165
+ return
166
+ }
167
+ let body = call.getString("body")
168
+ if let bodyBytes = body?.data(using: .utf8), bodyBytes.count > maxRequestBodyBytes {
169
+ call.reject("Request body is too large")
170
+ return
171
+ }
172
+
173
+ let headers = call.getObject("headers") ?? [:]
174
+ sendJSON(
175
+ endpoint: endpoint,
176
+ path: path,
177
+ method: method,
178
+ headers: headers,
179
+ body: body,
180
+ timeoutMs: timeoutMs(from: call)
181
+ ) { result in
182
+ switch result {
183
+ case .success(let response):
184
+ call.resolve([
185
+ "status": response.status,
186
+ "statusText": response.statusText,
187
+ "headers": response.headers,
188
+ "body": response.body,
189
+ ])
190
+ case .failure(let error):
191
+ call.reject("Local agent request failed: \(error.localizedDescription)")
192
+ }
193
+ }
194
+ }
195
+
196
+ private func ensureConversation(
197
+ endpoint: AgentEndpoint,
198
+ timeoutMs: Int,
199
+ completion: @escaping (Result<String, Error>) -> Void
200
+ ) {
201
+ let baseKey = endpoint.baseURL.absoluteString
202
+ if let existing = Self.conversationIdByBaseURL[baseKey], !existing.isEmpty {
203
+ completion(.success(existing))
204
+ return
205
+ }
206
+
207
+ sendJSON(
208
+ endpoint: endpoint,
209
+ path: "/api/conversations",
210
+ method: "POST",
211
+ headers: ["Content-Type": "application/json"],
212
+ body: "{\"title\":\"Quick Chat\"}",
213
+ timeoutMs: timeoutMs
214
+ ) { result in
215
+ switch result {
216
+ case .success(let response):
217
+ guard self.isHTTPSuccess(response.status) else {
218
+ completion(.failure(self.pluginError(self.httpErrorMessage(prefix: "Failed to create conversation", response: response))))
219
+ return
220
+ }
221
+ guard let payload = self.parseJSONObject(response.body),
222
+ let conversation = payload["conversation"] as? JSObject,
223
+ let id = conversation["id"] as? String,
224
+ !id.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else {
225
+ completion(.failure(self.pluginError("Conversation create response missing id")))
226
+ return
227
+ }
228
+ Self.conversationIdByBaseURL[baseKey] = id
229
+ completion(.success(id))
230
+ case .failure(let error):
231
+ completion(.failure(self.pluginError("Failed to create conversation: \(error.localizedDescription)")))
232
+ }
233
+ }
234
+ }
235
+
236
+ private func sendChatMessage(
237
+ endpoint: AgentEndpoint,
238
+ conversationId: String,
239
+ text: String,
240
+ timeoutMs: Int,
241
+ retryOnMissingConversation: Bool,
242
+ completion: @escaping (Result<JSObject, Error>) -> Void
243
+ ) {
244
+ let path = "/api/conversations/\(urlEncode(conversationId))/messages"
245
+ let bodyObject: JSObject = [
246
+ "text": text,
247
+ "channelType": "DM",
248
+ ]
249
+ guard let bodyData = try? JSONSerialization.data(withJSONObject: bodyObject, options: []),
250
+ let body = String(data: bodyData, encoding: .utf8) else {
251
+ completion(.failure(pluginError("Failed to encode chat request")))
252
+ return
253
+ }
254
+
255
+ sendJSON(
256
+ endpoint: endpoint,
257
+ path: path,
258
+ method: "POST",
259
+ headers: ["Content-Type": "application/json"],
260
+ body: body,
261
+ timeoutMs: timeoutMs
262
+ ) { result in
263
+ switch result {
264
+ case .success(let response):
265
+ if response.status == 404 && retryOnMissingConversation {
266
+ Self.conversationIdByBaseURL.removeValue(forKey: endpoint.baseURL.absoluteString)
267
+ self.ensureConversation(endpoint: endpoint, timeoutMs: timeoutMs) { nextConversation in
268
+ switch nextConversation {
269
+ case .success(let nextId):
270
+ self.sendChatMessage(
271
+ endpoint: endpoint,
272
+ conversationId: nextId,
273
+ text: text,
274
+ timeoutMs: timeoutMs,
275
+ retryOnMissingConversation: false,
276
+ completion: completion
277
+ )
278
+ case .failure(let error):
279
+ completion(.failure(error))
280
+ }
281
+ }
282
+ return
283
+ }
284
+ guard self.isHTTPSuccess(response.status) else {
285
+ completion(.failure(self.pluginError(self.httpErrorMessage(prefix: "Chat request failed", response: response))))
286
+ return
287
+ }
288
+ let payload = self.parseJSONObject(response.body) ?? [:]
289
+ let responseText = (payload["text"] as? String) ?? ""
290
+ let agentName = (payload["agentName"] as? String) ?? "Agent"
291
+ completion(.success([
292
+ "text": responseText,
293
+ "agentName": agentName,
294
+ ]))
295
+ case .failure(let error):
296
+ completion(.failure(self.pluginError("Chat request failed: \(error.localizedDescription)")))
297
+ }
298
+ }
299
+ }
300
+
301
+ private func sendJSON(
302
+ endpoint: AgentEndpoint,
303
+ path: String,
304
+ method: String,
305
+ headers: JSObject = [:],
306
+ body: String? = nil,
307
+ timeoutMs: Int,
308
+ completion: @escaping (Result<AgentHTTPResponse, Error>) -> Void
309
+ ) {
310
+ guard let url = URL(string: path, relativeTo: endpoint.baseURL)?.absoluteURL else {
311
+ completion(.failure(pluginError("Invalid local agent request path")))
312
+ return
313
+ }
314
+
315
+ var request = URLRequest(url: url)
316
+ request.httpMethod = method
317
+ request.timeoutInterval = TimeInterval(timeoutMs) / 1_000
318
+ request.cachePolicy = .reloadIgnoringLocalCacheData
319
+
320
+ for (key, value) in headers {
321
+ let normalizedKey = key.trimmingCharacters(in: .whitespacesAndNewlines)
322
+ guard !normalizedKey.isEmpty,
323
+ !isBlockedHeader(normalizedKey),
324
+ let stringValue = value as? String,
325
+ !stringValue.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else {
326
+ continue
327
+ }
328
+ request.setValue(stringValue, forHTTPHeaderField: normalizedKey)
329
+ }
330
+
331
+ if let token = endpoint.token, request.value(forHTTPHeaderField: "Authorization") == nil {
332
+ request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
333
+ }
334
+
335
+ if let body = body, method != "GET", method != "HEAD" {
336
+ let bodyData = body.data(using: .utf8) ?? Data()
337
+ if bodyData.count > maxRequestBodyBytes {
338
+ completion(.failure(pluginError("Request body is too large")))
339
+ return
340
+ }
341
+ request.httpBody = bodyData
342
+ if request.value(forHTTPHeaderField: "Content-Type") == nil {
343
+ request.setValue("application/json", forHTTPHeaderField: "Content-Type")
344
+ }
345
+ }
346
+
347
+ URLSession.shared.dataTask(with: request) { data, response, error in
348
+ if let error = error {
349
+ completion(.failure(error))
350
+ return
351
+ }
352
+ guard let httpResponse = response as? HTTPURLResponse else {
353
+ completion(.failure(self.pluginError("Agent endpoint returned a non-HTTP response")))
354
+ return
355
+ }
356
+ let responseData = data ?? Data()
357
+ if responseData.count > maxResponseBodyBytes {
358
+ completion(.failure(self.pluginError("Response body is too large")))
359
+ return
360
+ }
361
+
362
+ var responseHeaders: [String: String] = [:]
363
+ for (key, value) in httpResponse.allHeaderFields {
364
+ guard let headerKey = key as? String else { continue }
365
+ responseHeaders[headerKey.lowercased()] = String(describing: value)
366
+ }
367
+
368
+ completion(.success(AgentHTTPResponse(
369
+ status: httpResponse.statusCode,
370
+ statusText: HTTPURLResponse.localizedString(forStatusCode: httpResponse.statusCode),
371
+ headers: responseHeaders,
372
+ body: String(data: responseData, encoding: .utf8) ?? ""
373
+ )))
374
+ }.resume()
375
+ }
376
+
377
+ private func resolveEndpoint(call: CAPPluginCall? = nil) -> AgentEndpoint? {
378
+ guard let rawBaseURL = readConfiguredString(
379
+ call: call,
380
+ keys: [
381
+ "apiBase",
382
+ "baseUrl",
383
+ "baseURL",
384
+ "agentApiBase",
385
+ "ELIZA_AGENT_API_BASE",
386
+ "ELIZA_API_BASE",
387
+ "MILADY_IOS_API_BASE",
388
+ "MILADY_IOS_REMOTE_API_BASE",
389
+ "MILADY_MOBILE_API_BASE",
390
+ "VITE_MILADY_IOS_API_BASE",
391
+ "VITE_MILADY_MOBILE_API_BASE",
392
+ "VITE_ELIZA_IOS_API_BASE",
393
+ ]
394
+ ) else {
395
+ return nil
396
+ }
397
+
398
+ let trimmed = rawBaseURL.trimmingCharacters(in: .whitespacesAndNewlines)
399
+ .trimmingCharacters(in: CharacterSet(charactersIn: "/"))
400
+ guard let baseURL = URL(string: trimmed),
401
+ let scheme = baseURL.scheme?.lowercased(),
402
+ scheme == "http" || scheme == "https",
403
+ baseURL.host != nil else {
404
+ return nil
405
+ }
406
+
407
+ let token = readConfiguredString(
408
+ call: call,
409
+ keys: [
410
+ "apiToken",
411
+ "token",
412
+ "agentApiToken",
413
+ "ELIZA_AGENT_API_TOKEN",
414
+ "ELIZA_API_TOKEN",
415
+ "MILADY_IOS_API_TOKEN",
416
+ "MILADY_IOS_REMOTE_API_TOKEN",
417
+ "MILADY_MOBILE_API_TOKEN",
418
+ "VITE_MILADY_IOS_API_TOKEN",
419
+ "VITE_MILADY_MOBILE_API_TOKEN",
420
+ "VITE_ELIZA_IOS_API_TOKEN",
421
+ ]
422
+ )
423
+
424
+ return AgentEndpoint(baseURL: baseURL, token: token)
425
+ }
426
+
427
+ private func readConfiguredString(call: CAPPluginCall?, keys: [String]) -> String? {
428
+ for key in keys {
429
+ if let value = call?.getString(key)?.trimmingCharacters(in: .whitespacesAndNewlines), !value.isEmpty {
430
+ return value
431
+ }
432
+ }
433
+
434
+ let pluginConfig = getConfig()
435
+ for key in keys {
436
+ if let value = pluginConfig.getString(key)?.trimmingCharacters(in: .whitespacesAndNewlines), !value.isEmpty {
437
+ return value
438
+ }
439
+ }
440
+
441
+ for key in keys {
442
+ if let value = Bundle.main.object(forInfoDictionaryKey: key) as? String {
443
+ let trimmed = value.trimmingCharacters(in: .whitespacesAndNewlines)
444
+ if !trimmed.isEmpty { return trimmed }
445
+ }
446
+ }
447
+
448
+ let environment = ProcessInfo.processInfo.environment
449
+ for key in keys {
450
+ if let value = environment[key]?.trimmingCharacters(in: .whitespacesAndNewlines), !value.isEmpty {
451
+ return value
452
+ }
453
+ }
454
+
455
+ let defaults = UserDefaults.standard
456
+ for key in keys {
457
+ if let value = defaults.string(forKey: key)?.trimmingCharacters(in: .whitespacesAndNewlines), !value.isEmpty {
458
+ return value
459
+ }
460
+ }
461
+
462
+ return nil
463
+ }
464
+
465
+ private func normalizedStatus(
466
+ _ payload: JSObject,
467
+ fallbackState: String,
468
+ endpoint: AgentEndpoint,
469
+ error: String?
470
+ ) -> JSObject {
471
+ let state = (payload["state"] as? String) ?? fallbackState
472
+ let agentName = payload["agentName"] as? String
473
+ let startedAt = payload["startedAt"] as? Double
474
+ ?? (payload["startedAt"] as? NSNumber)?.doubleValue
475
+ ?? (payload["started_at"] as? NSNumber)?.doubleValue
476
+ let rawError = error ?? payload["error"] as? String
477
+ return status(
478
+ state: state,
479
+ agentName: agentName,
480
+ port: (payload["port"] as? Int)
481
+ ?? (payload["port"] as? NSNumber)?.intValue
482
+ ?? port(from: endpoint.baseURL),
483
+ startedAt: startedAt,
484
+ error: rawError
485
+ )
486
+ }
487
+
488
+ private func status(
489
+ state: String,
490
+ agentName: String?,
491
+ port: Int?,
492
+ startedAt: Double?,
493
+ error: String?
494
+ ) -> JSObject {
495
+ return [
496
+ "state": state,
497
+ "agentName": agentName ?? NSNull(),
498
+ "port": port ?? NSNull(),
499
+ "startedAt": startedAt ?? NSNull(),
500
+ "error": error ?? NSNull(),
501
+ ]
502
+ }
503
+
504
+ private func timeoutMs(from call: CAPPluginCall, defaultValue: Int = 10_000) -> Int {
505
+ let value = call.getInt("timeoutMs") ?? defaultValue
506
+ return min(120_000, max(1_000, value))
507
+ }
508
+
509
+ private func port(from url: URL) -> Int? {
510
+ if let port = url.port { return port }
511
+ if url.scheme?.lowercased() == "http" { return 80 }
512
+ if url.scheme?.lowercased() == "https" { return 443 }
513
+ return nil
514
+ }
515
+
516
+ private func isSafeLocalPath(_ path: String) -> Bool {
517
+ if !path.hasPrefix("/") || path.hasPrefix("//") { return false }
518
+ if path.range(of: "^[a-zA-Z][a-zA-Z0-9+.-]*://", options: .regularExpression) != nil {
519
+ return false
520
+ }
521
+ return true
522
+ }
523
+
524
+ private func isBlockedHeader(_ key: String) -> Bool {
525
+ switch key.lowercased() {
526
+ case "host", "connection", "content-length":
527
+ return true
528
+ default:
529
+ return false
530
+ }
531
+ }
532
+
533
+ private func isHTTPSuccess(_ status: Int) -> Bool {
534
+ return status >= 200 && status < 300
535
+ }
536
+
537
+ private func parseJSONObject(_ body: String) -> JSObject? {
538
+ guard let data = body.data(using: .utf8),
539
+ let object = try? JSONSerialization.jsonObject(with: data, options: []),
540
+ let json = object as? JSObject else {
541
+ return nil
542
+ }
543
+ return json
544
+ }
545
+
546
+ private func httpErrorMessage(prefix: String, response: AgentHTTPResponse) -> String {
547
+ let body = response.body.trimmingCharacters(in: .whitespacesAndNewlines)
548
+ if body.isEmpty {
549
+ return "\(prefix): HTTP \(response.status)"
550
+ }
551
+ return "\(prefix): HTTP \(response.status): \(body)"
552
+ }
553
+
554
+ private func missingEndpointMessage() -> String {
555
+ return "iOS Agent requires a configured HTTP endpoint. Set Agent.apiBase in capacitor.config, an Info.plist/UserDefaults key such as MILADY_IOS_API_BASE or ELIZA_AGENT_API_BASE, or a simulator environment variable. iOS does not bundle a Bun local runtime."
556
+ }
557
+
558
+ private func urlEncode(_ value: String) -> String {
559
+ return value.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? value
560
+ }
561
+
562
+ private func pluginError(_ message: String) -> NSError {
563
+ return NSError(domain: "AgentPlugin", code: 1, userInfo: [NSLocalizedDescriptionKey: message])
564
+ }
565
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elizaos/capacitor-agent",
3
- "version": "1.0.0",
3
+ "version": "2.0.0-beta.1",
4
4
  "description": "Starts, stops, and monitors the embedded Eliza agent runtime.",
5
5
  "keywords": [
6
6
  "agent-runtime",
@@ -21,26 +21,31 @@
21
21
  },
22
22
  "unpkg": "dist/plugin.js",
23
23
  "files": [
24
- "dist/"
24
+ "android/src/main/",
25
+ "android/build.gradle",
26
+ "dist/",
27
+ "ios/Sources/",
28
+ "*.podspec",
29
+ "dist"
25
30
  ],
26
31
  "author": "elizaOS",
27
32
  "license": "MIT",
28
33
  "repository": {
29
34
  "type": "git",
30
35
  "url": "https://github.com/elizaOS/eliza.git",
31
- "directory": "apps/app/plugins/agent"
36
+ "directory": "packages/native-plugins/agent"
32
37
  },
33
38
  "scripts": {
34
- "build": "npm run clean && tsc && rollup -c rollup.config.mjs",
35
- "clean": "rimraf ./dist",
36
- "prepublishOnly": "npm run build",
39
+ "build": "bun run clean && tsc && bun --bun rollup -c rollup.config.mjs",
40
+ "clean": "node ../../../scripts/rm-path-recursive.mjs dist",
41
+ "prepublishOnly": "bun run build",
37
42
  "watch": "tsc --watch"
38
43
  },
39
44
  "devDependencies": {
40
45
  "@capacitor/core": "^8.3.1",
41
46
  "rimraf": "^6.0.0",
42
47
  "rollup": "^4.60.2",
43
- "typescript": "^6.0.0"
48
+ "typescript": "^6.0.3"
44
49
  },
45
50
  "peerDependencies": {
46
51
  "@capacitor/core": "^8.3.1"