@pasko70/pibo 1.0.5 → 1.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 (29) hide show
  1. package/README.md +5 -1
  2. package/dist/apps/chat/agent-profiles.js +26 -4
  3. package/dist/apps/chat/model-catalog.js +42 -0
  4. package/dist/apps/chat/web-app.js +192 -7
  5. package/dist/apps/chat-ui/assets/{dist-aMr2VYOu.js → dist-8e4L8ciw.js} +1 -1
  6. package/dist/apps/chat-ui/assets/{dist-BGxHKHPX.js → dist-B7bbI3Qz.js} +1 -1
  7. package/dist/apps/chat-ui/assets/{dist-u2OzzOTm.js → dist-CMZOa5ik.js} +1 -1
  8. package/dist/apps/chat-ui/assets/{dist-CI0Xj2Cp.js → dist-CNLWH2qh.js} +1 -1
  9. package/dist/apps/chat-ui/assets/{dist-zgYUl2B-.js → dist-CUqpST5w.js} +1 -1
  10. package/dist/apps/chat-ui/assets/{dist-wiRpAHIv.js → dist-CqqUC8Ce.js} +1 -1
  11. package/dist/apps/chat-ui/assets/{dist-CNlhGq5i.js → dist-CspjOeBj.js} +1 -1
  12. package/dist/apps/chat-ui/assets/{dist-CaNOvqMY.js → dist-D2N4-LIc.js} +1 -1
  13. package/dist/apps/chat-ui/assets/{dist-DpmEro5R.js → dist-D9L4MSRF.js} +1 -1
  14. package/dist/apps/chat-ui/assets/{dist-Di1ScJ22.js → dist-DNcnQRPF.js} +1 -1
  15. package/dist/apps/chat-ui/assets/{dist-DrM-H3e1.js → dist-v4pjHlB7.js} +1 -1
  16. package/dist/apps/chat-ui/assets/index-D2Qxambd.js +151 -0
  17. package/dist/apps/chat-ui/assets/{index-Dk-opWl3.css → index-DXx368XK.css} +1 -1
  18. package/dist/apps/chat-ui/index.html +2 -2
  19. package/dist/gateway/server.js +2 -0
  20. package/dist/plugins/builtin.js +2 -1
  21. package/dist/plugins/registry.js +17 -1
  22. package/dist/user-skills/installer.js +211 -0
  23. package/dist/user-skills/manager.js +35 -0
  24. package/dist/user-skills/store.js +228 -0
  25. package/dist/user-skills/types.js +1 -0
  26. package/package.json +3 -3
  27. package/dist/apps/chat-ui/assets/index-B_E935fP.js +0 -151
  28. /package/{.codex/skills → skills/builtin}/pi-agent-harness/SKILL.md +0 -0
  29. /package/{.codex/skills → skills/builtin}/pi-agent-harness/agents/openai.yaml +0 -0
package/README.md CHANGED
@@ -111,6 +111,10 @@ Custom agents can be archived before deletion. Archived custom agents are remove
111
111
 
112
112
  The designer configures native Pibo agent capabilities only: plugin-registered tools, skills, context files, subagents, automatic local context-file loading, built-in Pi tool visibility, and capability packages such as `pibo-run-control`. Curated external CLI tools from `pibo tools` remain global operator tooling and are not selected per agent.
113
113
 
114
+ The Chat Web App also supports User Skills. Operators can create local skills or import them from `skills.sh` or GitHub, and Pibo stores them under `.pibo/user-skills` plus `.pibo/user-skills.json`. Enabled user skills are registered live so they are selectable in the Agent Designer and available to routed sessions without a manual restart.
115
+
116
+ User Skill names are guarded at two layers: the web app no longer re-registers an already-synced skill on subsequent requests, and create/rename/enable/import flows reject names that would collide with an already registered skill. Imports also refuse to silently overwrite an existing skill name.
117
+
114
118
  The Chat Web App now also has a dedicated Context area at `/apps/chat/context`. It reuses the managed context-file APIs inside the main Chat UI shell so operators can create, edit, relocate, and remove managed context files without leaving the authenticated Chat Web App. Plugin context files are shown there as read-only sources, and both the Context area and Agent Designer can create linked managed copies when a user wants to customize shipped content safely.
115
119
 
116
120
  The Context area also exposes the Pibo Base Prompt. The library prompt lives at `context/pibo-system-prompt.md`; the Chat Web App can switch between that read-only library prompt and a persisted custom prompt stored under `.pibo/base-prompt.md`. Runtime prompt templates replace `{{availableTools}}` and `{{guidelines}}` from the active Pi/Pibo tool surface before project context and skills are appended.
@@ -119,7 +123,7 @@ The Context area also exposes the Pibo Compaction Prompt. The library prompt liv
119
123
 
120
124
  ## Profiles
121
125
 
122
- The default profile is registered by the core plugin. It loads the local `pi-agent-harness` skill and uses Pi Coding Agent's built-in tools for normal coding work.
126
+ The default profile is registered by the core plugin. It loads the built-in `pi-agent-harness` skill from `skills/builtin/pi-agent-harness/SKILL.md` and uses Pi Coding Agent's built-in tools for normal coding work.
123
127
 
124
128
  The `codex` alias resolves to the `codex-compat-openai-web` profile. It keeps the Pibo runtime boundary while exposing Codex-like coding affordances: Pi/Pibo `read`, `edit`, and `write`; Pibo run-control `bash`; native `web_search`; `apply_patch` and `view_image`; generated `pibo_subagent_default`, `pibo_subagent_explorer`, and `pibo_subagent_worker`; and the `pibo_run_*` lifecycle tools. `web_search` is a normal Pibo native tool with a provider adapter; the default adapter injects OpenAI Responses hosted `web_search` into the model request instead of using a local DuckDuckGo function tool. It intentionally does not expose Pi's separate `grep`, `find`, or `ls` tools by default; codebase search remains Codex-style through `bash` and commands such as `rg`.
125
129
 
@@ -16,10 +16,26 @@ export function createCustomAgentProfileDefinition(agent) {
16
16
  builder.withMainModel(agent.mainModel);
17
17
  if (agent.subagentModel)
18
18
  builder.withSubagentModel(agent.subagentModel);
19
- for (const skillName of agent.skills)
20
- builder.addSkill(context.getSkill(skillName));
21
- for (const contextFileKey of agent.contextFiles)
22
- builder.addContextFile(context.getContextFile(contextFileKey));
19
+ for (const skillName of agent.skills) {
20
+ try {
21
+ builder.addSkill(context.getSkill(skillName));
22
+ }
23
+ catch (error) {
24
+ if (!isUnknownSkillError(error, skillName))
25
+ throw error;
26
+ console.warn(`Skipping unknown skill "${skillName}" for custom agent "${agent.profileName}"`);
27
+ }
28
+ }
29
+ for (const contextFileKey of agent.contextFiles) {
30
+ try {
31
+ builder.addContextFile(context.getContextFile(contextFileKey));
32
+ }
33
+ catch (error) {
34
+ if (!isUnknownContextFileError(error, contextFileKey))
35
+ throw error;
36
+ console.warn(`Skipping unknown context file "${contextFileKey}" for custom agent "${agent.profileName}"`);
37
+ }
38
+ }
23
39
  for (const toolName of agent.nativeTools)
24
40
  builder.addTool(context.getTool(toolName));
25
41
  for (const subagent of agent.subagents)
@@ -28,3 +44,9 @@ export function createCustomAgentProfileDefinition(agent) {
28
44
  },
29
45
  };
30
46
  }
47
+ function isUnknownContextFileError(error, contextFileKey) {
48
+ return error instanceof Error && error.message === `Unknown context file "${contextFileKey}"`;
49
+ }
50
+ function isUnknownSkillError(error, skillName) {
51
+ return error instanceof Error && error.message === `Unknown skill "${skillName}"`;
52
+ }
@@ -0,0 +1,42 @@
1
+ import { createAgentSessionServices } from "@mariozechner/pi-coding-agent";
2
+ export function buildModelCatalogFromRegistry(registry) {
3
+ const providers = new Map();
4
+ for (const model of registry.getAll()) {
5
+ const providerId = model.provider;
6
+ let provider = providers.get(providerId);
7
+ if (!provider) {
8
+ const authConfigured = registry.getProviderAuthStatus?.(providerId).configured ?? false;
9
+ provider = {
10
+ id: providerId,
11
+ label: registry.getProviderDisplayName?.(providerId) ?? providerId,
12
+ authConfigured,
13
+ models: [],
14
+ };
15
+ providers.set(providerId, provider);
16
+ }
17
+ provider.models.push({
18
+ provider: providerId,
19
+ id: model.id,
20
+ label: model.name || model.id,
21
+ authConfigured: provider.authConfigured,
22
+ supportsReasoning: model.reasoning || undefined,
23
+ });
24
+ }
25
+ return {
26
+ providers: [...providers.values()]
27
+ .sort((left, right) => left.label.localeCompare(right.label) || left.id.localeCompare(right.id))
28
+ .map((provider) => ({
29
+ ...provider,
30
+ models: [...provider.models].sort((left, right) => left.label.localeCompare(right.label) || left.id.localeCompare(right.id)),
31
+ })),
32
+ };
33
+ }
34
+ export async function loadModelCatalog(cwd = process.cwd()) {
35
+ try {
36
+ const services = await createAgentSessionServices({ cwd });
37
+ return buildModelCatalogFromRegistry(services.modelRegistry);
38
+ }
39
+ catch {
40
+ return { providers: [] };
41
+ }
42
+ }
@@ -13,6 +13,7 @@ import { isChatWebSessionArchived, withChatWebArchived } from "./session-metadat
13
13
  import { CustomAgentStore, createDefaultCustomAgentStore, isValidCustomAgentName, } from "./agent-store.js";
14
14
  import { loadPiboModelDefaults, savePiboModelDefaults, } from "../../core/model-defaults.js";
15
15
  import { createCustomAgentProfileDefinition } from "./agent-profiles.js";
16
+ import { loadModelCatalog } from "./model-catalog.js";
16
17
  import { createDefaultPiboReliabilityStore, PiboReliabilityStore } from "../../reliability/store.js";
17
18
  import { listMcpServerInfos, setMcpServerDescription } from "../../mcp/agent-context.js";
18
19
  import { readPiboBasePrompt, savePiboCustomBasePrompt, setPiboBasePromptMode, } from "../../core/base-prompt.js";
@@ -20,6 +21,7 @@ import { readPiboCompactionPrompt, savePiboCustomCompactionPrompt, setPiboCompac
20
21
  import { getDefaultPiboWorkspace } from "../../core/workspace.js";
21
22
  import { inspectPiPackageSource } from "../../pi-packages/metadata.js";
22
23
  import { findPiPackage, listPiPackages, removePiPackage, setPiPackageEnabled, upsertPiPackage } from "../../pi-packages/store.js";
24
+ import { UserSkillManager } from "../../user-skills/manager.js";
23
25
  export const CHAT_WEB_APP_NAME = "pibo.chat-web";
24
26
  export const CHAT_WEB_CHANNEL = "pibo.chat-web";
25
27
  export const CHAT_WEB_MOUNT_PATH = "/apps/chat";
@@ -390,6 +392,59 @@ function normalizeCompactionPromptMarkdown(value) {
390
392
  throw new PiboWebHttpError("markdown must be a string", 400);
391
393
  return value;
392
394
  }
395
+ function normalizeUserSkillName(value) {
396
+ if (typeof value !== "string" || value.trim().length === 0) {
397
+ throw new PiboWebHttpError("Skill name is required", 400);
398
+ }
399
+ const name = value.trim();
400
+ if (name.length > 64)
401
+ throw new PiboWebHttpError("Skill name is too long", 400);
402
+ if (!/^[a-z][a-z0-9-]*$/.test(name)) {
403
+ throw new PiboWebHttpError("Skill name must be lowercase kebab-case, e.g. my-skill", 400);
404
+ }
405
+ return name;
406
+ }
407
+ function normalizeUserSkillDescription(value) {
408
+ if (typeof value !== "string")
409
+ throw new PiboWebHttpError("Skill description must be a string", 400);
410
+ return value.trim();
411
+ }
412
+ function normalizeUserSkillMarkdown(value) {
413
+ if (typeof value !== "string")
414
+ throw new PiboWebHttpError("Skill markdown must be a string", 400);
415
+ return value;
416
+ }
417
+ function normalizeUserSkillEnabled(value) {
418
+ if (value === undefined)
419
+ return undefined;
420
+ if (typeof value !== "boolean")
421
+ throw new PiboWebHttpError("enabled must be a boolean", 400);
422
+ return value;
423
+ }
424
+ function normalizeUserSkillUrl(value) {
425
+ if (typeof value !== "string" || value.trim().length === 0) {
426
+ throw new PiboWebHttpError("Skill URL is required", 400);
427
+ }
428
+ const url = value.trim();
429
+ if (!url.startsWith("http://") && !url.startsWith("https://") && !url.includes("/")) {
430
+ throw new PiboWebHttpError("Skill URL must be a valid URL or owner/repo shorthand", 400);
431
+ }
432
+ return url;
433
+ }
434
+ function userSkillResourceId(pathname) {
435
+ const prefix = `${CHAT_WEB_API_PREFIX}/user-skills/`;
436
+ if (!pathname.startsWith(prefix))
437
+ return undefined;
438
+ const encodedId = pathname.slice(prefix.length);
439
+ if (!encodedId || encodedId.includes("/"))
440
+ return undefined;
441
+ try {
442
+ return decodeURIComponent(encodedId);
443
+ }
444
+ catch {
445
+ throw new PiboWebHttpError("Invalid user skill id", 400);
446
+ }
447
+ }
393
448
  function normalizeAgentArchived(value) {
394
449
  if (value === undefined)
395
450
  return undefined;
@@ -743,6 +798,52 @@ function ensureCustomAgentProfiles(state, context) {
743
798
  context.channelContext.upsertProfile(createCustomAgentProfileDefinition(agent));
744
799
  }
745
800
  }
801
+ function serializeCustomAgent(agent, context) {
802
+ return {
803
+ ...agent,
804
+ brokenContextFiles: listBrokenContextFiles(agent.contextFiles, context),
805
+ };
806
+ }
807
+ function serializeCustomAgents(agents, context) {
808
+ return agents.map((agent) => serializeCustomAgent(agent, context));
809
+ }
810
+ function listBrokenContextFiles(keys, context) {
811
+ const catalog = context.channelContext.getCapabilityCatalog?.();
812
+ if (!catalog)
813
+ return [];
814
+ const knownKeys = new Set(catalog.contextFiles.map((contextFile) => contextFile.key));
815
+ return keys.filter((key) => !knownKeys.has(key));
816
+ }
817
+ function syncUserSkills(state, context) {
818
+ const registerSkill = context.channelContext.registerSkill;
819
+ const unregisterSkill = context.channelContext.unregisterSkill;
820
+ if (!registerSkill || !unregisterSkill)
821
+ return;
822
+ const userSkills = state.userSkillManager.list();
823
+ const enabledNames = new Set(userSkills.filter((s) => s.enabled).map((s) => s.name));
824
+ const previouslySyncedNames = state.syncedUserSkillNames ?? new Set();
825
+ // Unregister disabled or removed user skills
826
+ for (const name of previouslySyncedNames) {
827
+ if (!enabledNames.has(name)) {
828
+ unregisterSkill(name);
829
+ }
830
+ }
831
+ // Register only newly enabled user skills. Re-registering an already synced
832
+ // skill would trip the registry duplicate-skill guard and break the web UI.
833
+ for (const skill of userSkills) {
834
+ if (skill.enabled && !previouslySyncedNames.has(skill.name)) {
835
+ registerSkill({ name: skill.name, path: skill.path, enabled: true });
836
+ }
837
+ }
838
+ state.syncedUserSkillNames = enabledNames;
839
+ }
840
+ function assertUserSkillNameIsAvailable(state, context, name, currentSkillId) {
841
+ const currentSkill = currentSkillId ? state.userSkillManager.get(currentSkillId) : undefined;
842
+ const conflict = (context.channelContext.getCapabilityCatalog?.().skills ?? []).find((skill) => (skill.name === name && (!currentSkill || currentSkill.name !== name)));
843
+ if (conflict) {
844
+ throw new PiboWebHttpError(`Skill name "${name}" conflicts with an existing registered skill`, 409);
845
+ }
846
+ }
746
847
  function createAgentInput(ownerScope, body) {
747
848
  return {
748
849
  ownerScope,
@@ -816,7 +917,7 @@ function requireOwnedAgent(agent, webSession) {
816
917
  }
817
918
  return agent;
818
919
  }
819
- async function buildAgentCatalog(context) {
920
+ async function buildAgentCatalog(context, state) {
820
921
  return {
821
922
  ...(context.channelContext.getCapabilityCatalog?.() ?? {
822
923
  nativeTools: [],
@@ -830,6 +931,7 @@ async function buildAgentCatalog(context) {
830
931
  }),
831
932
  mcpServers: await listMcpServerInfos(),
832
933
  piPackages: listPiPackages(),
934
+ userSkills: state.userSkillManager.list(),
833
935
  };
834
936
  }
835
937
  function agentsSelectingPiPackage(state, packageId) {
@@ -2103,6 +2205,7 @@ export function createChatWebApp(options = {}) {
2103
2205
  reliabilityStore: createReliabilityStore(options.reliabilityStorePath),
2104
2206
  traceCache: new Map(),
2105
2207
  liveListeners: new Set(),
2208
+ userSkillManager: new UserSkillManager(process.cwd()),
2106
2209
  };
2107
2210
  const requireSession = (request, context) => context.requireSession({
2108
2211
  request,
@@ -2115,6 +2218,7 @@ export function createChatWebApp(options = {}) {
2115
2218
  const url = new URL(request.url);
2116
2219
  ensureEventIndexing(state, context);
2117
2220
  ensureCustomAgentProfiles(state, context);
2221
+ syncUserSkills(state, context);
2118
2222
  const builtAsset = responseBuiltChatAsset(request, url.pathname);
2119
2223
  if (builtAsset)
2120
2224
  return builtAsset;
@@ -2162,9 +2266,10 @@ export function createChatWebApp(options = {}) {
2162
2266
  rooms,
2163
2267
  sessions,
2164
2268
  agents: context.channelContext.getProfiles?.() ?? [],
2165
- customAgents: state.agentStore.list(webSession.ownerScope, { includeArchived: true }),
2269
+ customAgents: serializeCustomAgents(state.agentStore.list(webSession.ownerScope, { includeArchived: true }), context),
2166
2270
  modelDefaults: loadChatModelDefaults(process.cwd()),
2167
- agentCatalog: await buildAgentCatalog(context),
2271
+ modelCatalog: await loadModelCatalog(process.cwd()),
2272
+ agentCatalog: await buildAgentCatalog(context, state),
2168
2273
  capabilities: {
2169
2274
  actions: context.channelContext.getGatewayActions(),
2170
2275
  },
@@ -2173,7 +2278,7 @@ export function createChatWebApp(options = {}) {
2173
2278
  if (url.pathname === `${CHAT_WEB_API_PREFIX}/agent-catalog` && request.method === "GET") {
2174
2279
  await requireSession(request, context);
2175
2280
  return responseJson({
2176
- catalog: await buildAgentCatalog(context),
2281
+ catalog: await buildAgentCatalog(context, state),
2177
2282
  profiles: context.channelContext.getProfiles?.() ?? [],
2178
2283
  });
2179
2284
  }
@@ -2243,6 +2348,86 @@ export function createChatWebApp(options = {}) {
2243
2348
  const removed = removePiPackage(piPackageId);
2244
2349
  return responseJson({ removedPackage: removed });
2245
2350
  }
2351
+ if (url.pathname === `${CHAT_WEB_API_PREFIX}/user-skills` && request.method === "GET") {
2352
+ await requireSession(request, context);
2353
+ return responseJson({ skills: state.userSkillManager.list() });
2354
+ }
2355
+ if (url.pathname === `${CHAT_WEB_API_PREFIX}/user-skills` && request.method === "POST") {
2356
+ requireSameOriginJsonRequest(request);
2357
+ await requireSession(request, context);
2358
+ const body = await readJsonBody(request);
2359
+ const name = normalizeUserSkillName(body.name);
2360
+ assertUserSkillNameIsAvailable(state, context, name);
2361
+ const skill = state.userSkillManager.create({
2362
+ name,
2363
+ description: normalizeUserSkillDescription(body.description ?? ""),
2364
+ markdown: normalizeUserSkillMarkdown(body.markdown ?? ""),
2365
+ });
2366
+ syncUserSkills(state, context);
2367
+ return responseJson({ skill }, { status: 201 });
2368
+ }
2369
+ if (url.pathname === `${CHAT_WEB_API_PREFIX}/user-skills/install` && request.method === "POST") {
2370
+ requireSameOriginJsonRequest(request);
2371
+ await requireSession(request, context);
2372
+ const body = await readJsonBody(request);
2373
+ const skill = await state.userSkillManager.installFromUrl(normalizeUserSkillUrl(body.url));
2374
+ try {
2375
+ assertUserSkillNameIsAvailable(state, context, skill.name, skill.id);
2376
+ }
2377
+ catch (error) {
2378
+ state.userSkillManager.remove(skill.id);
2379
+ throw error;
2380
+ }
2381
+ syncUserSkills(state, context);
2382
+ return responseJson({ skill }, { status: 201 });
2383
+ }
2384
+ const userSkillId = userSkillResourceId(url.pathname);
2385
+ if (userSkillId && request.method === "GET") {
2386
+ await requireSession(request, context);
2387
+ const skill = state.userSkillManager.get(userSkillId);
2388
+ if (!skill)
2389
+ throw new PiboWebHttpError("Skill not found", 404);
2390
+ const markdown = state.userSkillManager.getSkillMarkdown(skill.id);
2391
+ return responseJson({ skill, markdown });
2392
+ }
2393
+ if (userSkillId && request.method === "PATCH") {
2394
+ requireSameOriginJsonRequest(request);
2395
+ await requireSession(request, context);
2396
+ const existing = state.userSkillManager.get(userSkillId);
2397
+ if (!existing)
2398
+ throw new PiboWebHttpError("Skill not found", 404);
2399
+ const body = await readJsonBody(request);
2400
+ const input = {};
2401
+ if (body.name !== undefined)
2402
+ input.name = normalizeUserSkillName(body.name);
2403
+ if (body.description !== undefined)
2404
+ input.description = normalizeUserSkillDescription(body.description);
2405
+ if (body.markdown !== undefined)
2406
+ input.markdown = normalizeUserSkillMarkdown(body.markdown);
2407
+ if (body.enabled !== undefined)
2408
+ input.enabled = normalizeUserSkillEnabled(body.enabled);
2409
+ if (Object.keys(input).length === 0) {
2410
+ throw new PiboWebHttpError("No skill update fields provided", 400);
2411
+ }
2412
+ const nextName = input.name ?? existing.name;
2413
+ const nextEnabled = input.enabled ?? existing.enabled;
2414
+ if (nextEnabled) {
2415
+ assertUserSkillNameIsAvailable(state, context, nextName, existing.id);
2416
+ }
2417
+ const skill = state.userSkillManager.update(existing.id, input);
2418
+ syncUserSkills(state, context);
2419
+ return responseJson({ skill });
2420
+ }
2421
+ if (userSkillId && request.method === "DELETE") {
2422
+ requireSameOriginJsonRequest(request);
2423
+ await requireSession(request, context);
2424
+ const existing = state.userSkillManager.get(userSkillId);
2425
+ if (!existing)
2426
+ throw new PiboWebHttpError("Skill not found", 404);
2427
+ state.userSkillManager.remove(existing.id);
2428
+ syncUserSkills(state, context);
2429
+ return responseJson({ removedSkillId: existing.id });
2430
+ }
2246
2431
  if (url.pathname === `${CHAT_WEB_API_PREFIX}/base-prompt` && request.method === "GET") {
2247
2432
  await requireSession(request, context);
2248
2433
  return responseJson({ basePrompt: await readPiboBasePrompt(process.cwd()) });
@@ -2286,7 +2471,7 @@ export function createChatWebApp(options = {}) {
2286
2471
  if (url.pathname === `${CHAT_WEB_API_PREFIX}/agents` && request.method === "GET") {
2287
2472
  const webSession = await requireSession(request, context);
2288
2473
  const includeArchived = parseBooleanSearchParam(url, "includeArchived");
2289
- return responseJson({ agents: state.agentStore.list(webSession.ownerScope, { includeArchived }) });
2474
+ return responseJson({ agents: serializeCustomAgents(state.agentStore.list(webSession.ownerScope, { includeArchived }), context) });
2290
2475
  }
2291
2476
  if (url.pathname === `${CHAT_WEB_API_PREFIX}/agents` && request.method === "POST") {
2292
2477
  requireSameOriginJsonRequest(request);
@@ -2296,7 +2481,7 @@ export function createChatWebApp(options = {}) {
2296
2481
  requireAgentProfileNameAvailable(state, context, input.displayName);
2297
2482
  const agent = state.agentStore.create(input);
2298
2483
  context.channelContext.upsertProfile?.(createCustomAgentProfileDefinition(agent));
2299
- return responseJson({ agent }, { status: 201 });
2484
+ return responseJson({ agent: serializeCustomAgent(agent, context) }, { status: 201 });
2300
2485
  }
2301
2486
  const patchAgentId = agentResourceId(url.pathname);
2302
2487
  if (patchAgentId && request.method === "PATCH") {
@@ -2320,7 +2505,7 @@ export function createChatWebApp(options = {}) {
2320
2505
  else {
2321
2506
  context.channelContext.upsertProfile?.(createCustomAgentProfileDefinition(owned));
2322
2507
  }
2323
- return responseJson({ agent: owned });
2508
+ return responseJson({ agent: serializeCustomAgent(owned, context) });
2324
2509
  }
2325
2510
  if (patchAgentId && request.method === "DELETE") {
2326
2511
  requireSameOriginJsonRequest(request);
@@ -1 +1 @@
1
- import{N as e,P as t,U as n,o as r,r as i}from"./dist-SVPsM5Oi.js";import{n as a,r as o}from"./dist-tGfufz3b.js";import{r as s}from"./dist-zgYUl2B-.js";import{html as c}from"./dist-wiRpAHIv.js";var l=1,u=33,d=34,f=35,p=36,m=new a(e=>{let t=e.pos;for(;;){if(e.next==10){e.advance();break}else if(e.next==123&&e.peek(1)==123||e.next<0)break;e.advance()}e.pos>t&&e.acceptToken(l)});function h(e,t,n){return new a(r=>{let i=r.pos;for(;r.next!=e&&r.next>=0&&(n||r.next!=38&&(r.next!=123||r.peek(1)!=123));)r.advance();r.pos>i&&r.acceptToken(t)})}var g=h(39,u,!1),_=h(34,d,!1),v=h(39,f,!0),y=h(34,p,!0),b=o.deserialize({version:14,states:"(jOVOqOOOeQpOOOvO!bO'#CaOOOP'#Cx'#CxQVOqOOO!OQpO'#CfO!WQpO'#ClO!]QpO'#CrO!bQpO'#CsOOQO'#Cv'#CvQ!gQpOOQ!lQpOOQ!qQpOOOOOV,58{,58{O!vOpO,58{OOOP-E6v-E6vO!{QpO,59QO#TQpO,59QOOQO,59W,59WO#YQpO,59^OOQO,59_,59_O#_QpOOO#_QpOOO#gQpOOOOOV1G.g1G.gO#oQpO'#CyO#tQpO1G.lOOQO1G.l1G.lO#|QpO1G.lOOQO1G.x1G.xO$UO`O'#DUO$ZOWO'#DUOOQO'#Co'#CoQOQpOOOOQO'#Cu'#CuO$`OtO'#CwO$qOrO'#CwOOQO,59e,59eOOQO-E6w-E6wOOQO7+$W7+$WO%SQpO7+$WO%[QpO7+$WOOOO'#Cp'#CpO%aOpO,59pOOOO'#Cq'#CqO%fOpO,59pOOOS'#Cz'#CzO%kOtO,59cOOQO,59c,59cOOOQ'#C{'#C{O%|OrO,59cO&_QpO<<GrOOQO<<Gr<<GrOOQO1G/[1G/[OOOS-E6x-E6xOOQO1G.}1G.}OOOQ-E6y-E6yOOQOAN=^AN=^",stateData:"&d~OvOS~OPROSQOVROWRO~OZTO[XO^VOaUOhWO~OR]OU^O~O[`O^aO~O[bO~O[cO~O[dO~ObeO~ObfO~ObgO~ORhO~O]kOwiO~O[lO~O_mO~OynOzoO~OysOztO~O[uO~O]wOwiO~O_yOwiO~OtzO~Os|O~OSQOV!OOW!OOr!OOy!QO~OSQOV!ROW!ROq!ROz!QO~O_!TOwiO~O]!UO~Oy!VO~Oz!VO~OSQOV!OOW!OOr!OOy!XO~OSQOV!ROW!ROq!ROz!XO~O]!ZO~O",goto:"#dyPPPPPzPPPP!WPPPPP!WPP!Z!^!a!d!dP!g!j!m!p!v#Q#WPPPPPPPP#^SROSS!Os!PT!Rt!SRYPRqeR{nR}oRZPRqfR[PRqgQSOR_SQj`SvjxRxlQ!PsR!W!PQ!StR!Y!SQpeRrf",nodeNames:`⚠ Text Content }} {{ Interpolation InterpolationContent Entity InvalidEntity Attribute BoundAttributeName [ Identifier ] ( ) ReferenceName # Is ExpressionAttributeValue AttributeInterpolation AttributeInterpolation EventName DirectiveName * StatementAttributeValue AttributeName AttributeValue`,maxTerm:42,nodeProps:[[`openedBy`,3,`{{`,15,`(`],[`closedBy`,4,`}}`,14,`)`],[`isolate`,-4,5,19,25,27,``]],skippedNodes:[0],repeatNodeCount:4,tokenData:"0r~RyOX#rXY$mYZ$mZ]#r]^$m^p#rpq$mqr#rrs%jst&Qtv#rvw&hwx)zxy*byz*xz{+`{}#r}!O+v!O!P-]!P!Q#r!Q![+v![!]+v!]!_#r!_!`-s!`!c#r!c!}+v!}#O.Z#O#P#r#P#Q.q#Q#R#r#R#S+v#S#T#r#T#o+v#o#p/X#p#q#r#q#r0Z#r%W#r%W;'S+v;'S;:j-V;:j;=`$g<%lO+vQ#wTUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rQ$ZSO#q#r#r;'S#r;'S;=`$g<%lO#rQ$jP;=`<%l#rR$t[UQvPOX#rXY$mYZ$mZ]#r]^$m^p#rpq$mq#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR%qTyPUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR&XTaPUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR&oXUQWPOp'[pq#rq!]'[!]!^#r!^#q'[#q#r(d#r;'S'[;'S;=`)t<%lO'[R'aXUQOp'[pq#rq!]'[!]!^'|!^#q'[#q#r(d#r;'S'[;'S;=`)t<%lO'[R(TTVPUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR(gXOp'[pq#rq!]'[!]!^'|!^#q'[#q#r)S#r;'S'[;'S;=`)t<%lO'[P)VUOp)Sq!])S!]!^)i!^;'S)S;'S;=`)n<%lO)SP)nOVPP)qP;=`<%l)SR)wP;=`<%l'[R*RTzPUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR*iT^PUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR+PT_PUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR+gThPUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR+}b[PUQO}#r}!O+v!O!Q#r!Q![+v![!]+v!]!c#r!c!}+v!}#R#r#R#S+v#S#T#r#T#o+v#o#q#r#q#r$W#r%W#r%W;'S+v;'S;:j-V;:j;=`$g<%lO+vR-YP;=`<%l+vR-dTwPUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR-zTUQbPO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR.bTZPUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR.xT]PUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR/^VUQO#o#r#o#p/s#p#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR/zTSPUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#r~0^TO#q#r#q#r0m#r;'S#r;'S;=`$g<%lO#r~0rOR~",tokenizers:[m,g,_,v,y,0,1],topRules:{Content:[0,2],Attribute:[1,9]},tokenPrec:0}),x=s.parser.configure({top:`SingleExpression`}),S=b.configure({props:[e({Text:t.content,Is:t.definitionOperator,AttributeName:t.attributeName,"AttributeValue ExpressionAttributeValue StatementAttributeValue":t.attributeValue,Entity:t.character,InvalidEntity:t.invalid,"BoundAttributeName/Identifier":t.attributeName,"EventName/Identifier":t.special(t.attributeName),"ReferenceName/Identifier":t.variableName,"DirectiveName/Identifier":t.keyword,"{{ }}":t.brace,"( )":t.paren,"[ ]":t.bracket,"# '*'":t.punctuation})]}),C={parser:x},w={parser:s.parser},T=S.configure({wrap:n((e,t)=>e.name==`InterpolationContent`?C:null)}),E=S.configure({wrap:n((e,t)=>e.name==`InterpolationContent`?C:e.name==`AttributeInterpolation`?e.node.parent?.name==`StatementAttributeValue`?w:C:null),top:`Attribute`}),D={parser:T},O={parser:E},k=c({selfClosingTags:!0});function A(e){return e.configure({wrap:n(M)},`angular`)}var j=A(k.language);function M(e,t){switch(e.name){case`Attribute`:return/^[*#(\[]|\{\{/.test(t.read(e.from,e.to))?O:null;case`Text`:return D}return null}function N(e={}){let t=k;if(e.base){if(e.base.language.name!=`html`||!(e.base.language instanceof i))throw RangeError(`The base option must be the result of calling html(...)`);t=e.base}return new r(t.language==k.language?j:A(t.language),[t.support,t.language.data.of({closeBrackets:{brackets:[`[`,`{`,`"`]},indentOnInput:/^\s*[\}\]]$/})])}export{N as angular};
1
+ import{N as e,P as t,U as n,o as r,r as i}from"./dist-SVPsM5Oi.js";import{n as a,r as o}from"./dist-tGfufz3b.js";import{r as s}from"./dist-CUqpST5w.js";import{html as c}from"./dist-CqqUC8Ce.js";var l=1,u=33,d=34,f=35,p=36,m=new a(e=>{let t=e.pos;for(;;){if(e.next==10){e.advance();break}else if(e.next==123&&e.peek(1)==123||e.next<0)break;e.advance()}e.pos>t&&e.acceptToken(l)});function h(e,t,n){return new a(r=>{let i=r.pos;for(;r.next!=e&&r.next>=0&&(n||r.next!=38&&(r.next!=123||r.peek(1)!=123));)r.advance();r.pos>i&&r.acceptToken(t)})}var g=h(39,u,!1),_=h(34,d,!1),v=h(39,f,!0),y=h(34,p,!0),b=o.deserialize({version:14,states:"(jOVOqOOOeQpOOOvO!bO'#CaOOOP'#Cx'#CxQVOqOOO!OQpO'#CfO!WQpO'#ClO!]QpO'#CrO!bQpO'#CsOOQO'#Cv'#CvQ!gQpOOQ!lQpOOQ!qQpOOOOOV,58{,58{O!vOpO,58{OOOP-E6v-E6vO!{QpO,59QO#TQpO,59QOOQO,59W,59WO#YQpO,59^OOQO,59_,59_O#_QpOOO#_QpOOO#gQpOOOOOV1G.g1G.gO#oQpO'#CyO#tQpO1G.lOOQO1G.l1G.lO#|QpO1G.lOOQO1G.x1G.xO$UO`O'#DUO$ZOWO'#DUOOQO'#Co'#CoQOQpOOOOQO'#Cu'#CuO$`OtO'#CwO$qOrO'#CwOOQO,59e,59eOOQO-E6w-E6wOOQO7+$W7+$WO%SQpO7+$WO%[QpO7+$WOOOO'#Cp'#CpO%aOpO,59pOOOO'#Cq'#CqO%fOpO,59pOOOS'#Cz'#CzO%kOtO,59cOOQO,59c,59cOOOQ'#C{'#C{O%|OrO,59cO&_QpO<<GrOOQO<<Gr<<GrOOQO1G/[1G/[OOOS-E6x-E6xOOQO1G.}1G.}OOOQ-E6y-E6yOOQOAN=^AN=^",stateData:"&d~OvOS~OPROSQOVROWRO~OZTO[XO^VOaUOhWO~OR]OU^O~O[`O^aO~O[bO~O[cO~O[dO~ObeO~ObfO~ObgO~ORhO~O]kOwiO~O[lO~O_mO~OynOzoO~OysOztO~O[uO~O]wOwiO~O_yOwiO~OtzO~Os|O~OSQOV!OOW!OOr!OOy!QO~OSQOV!ROW!ROq!ROz!QO~O_!TOwiO~O]!UO~Oy!VO~Oz!VO~OSQOV!OOW!OOr!OOy!XO~OSQOV!ROW!ROq!ROz!XO~O]!ZO~O",goto:"#dyPPPPPzPPPP!WPPPPP!WPP!Z!^!a!d!dP!g!j!m!p!v#Q#WPPPPPPPP#^SROSS!Os!PT!Rt!SRYPRqeR{nR}oRZPRqfR[PRqgQSOR_SQj`SvjxRxlQ!PsR!W!PQ!StR!Y!SQpeRrf",nodeNames:`⚠ Text Content }} {{ Interpolation InterpolationContent Entity InvalidEntity Attribute BoundAttributeName [ Identifier ] ( ) ReferenceName # Is ExpressionAttributeValue AttributeInterpolation AttributeInterpolation EventName DirectiveName * StatementAttributeValue AttributeName AttributeValue`,maxTerm:42,nodeProps:[[`openedBy`,3,`{{`,15,`(`],[`closedBy`,4,`}}`,14,`)`],[`isolate`,-4,5,19,25,27,``]],skippedNodes:[0],repeatNodeCount:4,tokenData:"0r~RyOX#rXY$mYZ$mZ]#r]^$m^p#rpq$mqr#rrs%jst&Qtv#rvw&hwx)zxy*byz*xz{+`{}#r}!O+v!O!P-]!P!Q#r!Q![+v![!]+v!]!_#r!_!`-s!`!c#r!c!}+v!}#O.Z#O#P#r#P#Q.q#Q#R#r#R#S+v#S#T#r#T#o+v#o#p/X#p#q#r#q#r0Z#r%W#r%W;'S+v;'S;:j-V;:j;=`$g<%lO+vQ#wTUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rQ$ZSO#q#r#r;'S#r;'S;=`$g<%lO#rQ$jP;=`<%l#rR$t[UQvPOX#rXY$mYZ$mZ]#r]^$m^p#rpq$mq#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR%qTyPUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR&XTaPUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR&oXUQWPOp'[pq#rq!]'[!]!^#r!^#q'[#q#r(d#r;'S'[;'S;=`)t<%lO'[R'aXUQOp'[pq#rq!]'[!]!^'|!^#q'[#q#r(d#r;'S'[;'S;=`)t<%lO'[R(TTVPUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR(gXOp'[pq#rq!]'[!]!^'|!^#q'[#q#r)S#r;'S'[;'S;=`)t<%lO'[P)VUOp)Sq!])S!]!^)i!^;'S)S;'S;=`)n<%lO)SP)nOVPP)qP;=`<%l)SR)wP;=`<%l'[R*RTzPUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR*iT^PUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR+PT_PUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR+gThPUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR+}b[PUQO}#r}!O+v!O!Q#r!Q![+v![!]+v!]!c#r!c!}+v!}#R#r#R#S+v#S#T#r#T#o+v#o#q#r#q#r$W#r%W#r%W;'S+v;'S;:j-V;:j;=`$g<%lO+vR-YP;=`<%l+vR-dTwPUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR-zTUQbPO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR.bTZPUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR.xT]PUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR/^VUQO#o#r#o#p/s#p#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#rR/zTSPUQO#q#r#q#r$W#r;'S#r;'S;=`$g<%lO#r~0^TO#q#r#q#r0m#r;'S#r;'S;=`$g<%lO#r~0rOR~",tokenizers:[m,g,_,v,y,0,1],topRules:{Content:[0,2],Attribute:[1,9]},tokenPrec:0}),x=s.parser.configure({top:`SingleExpression`}),S=b.configure({props:[e({Text:t.content,Is:t.definitionOperator,AttributeName:t.attributeName,"AttributeValue ExpressionAttributeValue StatementAttributeValue":t.attributeValue,Entity:t.character,InvalidEntity:t.invalid,"BoundAttributeName/Identifier":t.attributeName,"EventName/Identifier":t.special(t.attributeName),"ReferenceName/Identifier":t.variableName,"DirectiveName/Identifier":t.keyword,"{{ }}":t.brace,"( )":t.paren,"[ ]":t.bracket,"# '*'":t.punctuation})]}),C={parser:x},w={parser:s.parser},T=S.configure({wrap:n((e,t)=>e.name==`InterpolationContent`?C:null)}),E=S.configure({wrap:n((e,t)=>e.name==`InterpolationContent`?C:e.name==`AttributeInterpolation`?e.node.parent?.name==`StatementAttributeValue`?w:C:null),top:`Attribute`}),D={parser:T},O={parser:E},k=c({selfClosingTags:!0});function A(e){return e.configure({wrap:n(M)},`angular`)}var j=A(k.language);function M(e,t){switch(e.name){case`Attribute`:return/^[*#(\[]|\{\{/.test(t.read(e.from,e.to))?O:null;case`Text`:return D}return null}function N(e={}){let t=k;if(e.base){if(e.base.language.name!=`html`||!(e.base.language instanceof i))throw RangeError(`The base option must be the result of calling html(...)`);t=e.base}return new r(t.language==k.language?j:A(t.language),[t.support,t.language.data.of({closeBrackets:{brackets:[`[`,`{`,`"`]},indentOnInput:/^\s*[\}\]]$/})])}export{N as angular};