@giselles-ai/agent 0.1.24 → 0.1.26

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.
@@ -7,7 +7,13 @@ function computeConfigHash(config) {
7
7
  files: (config.files ?? []).map((f) => ({
8
8
  path: f.path,
9
9
  content: f.content
10
- }))
10
+ })),
11
+ setup: config.setup?.script ?? null,
12
+ env: config.env ? Object.fromEntries(
13
+ Object.entries(config.env).sort(
14
+ ([a], [b]) => a < b ? -1 : a > b ? 1 : 0
15
+ )
16
+ ) : null
11
17
  });
12
18
  return createHash("sha256").update(payload).digest("hex").slice(0, 16);
13
19
  }
@@ -50,7 +56,9 @@ async function requestBuild(agent, options) {
50
56
  const requestBody = {
51
57
  config_hash: configHash,
52
58
  agent_type: agent.agentType ?? "gemini",
53
- files
59
+ files,
60
+ setup_script: agent.setup?.script ?? null,
61
+ env: agent.env ?? null
54
62
  };
55
63
  const requestHeaders = {
56
64
  "content-type": "application/json",
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { A as AgentConfig, D as DefinedAgent } from './types-Cto-uejG.js';
2
- export { a as AgentFile } from './types-Cto-uejG.js';
1
+ import { A as AgentConfig, D as DefinedAgent } from './types-Co_KfALw.js';
2
+ export { a as AgentFile, b as AgentSetup, U as UICatalog } from './types-Co_KfALw.js';
3
3
 
4
4
  declare function defineAgent(config: AgentConfig): DefinedAgent;
5
5
 
package/dist/index.js CHANGED
@@ -1,14 +1,23 @@
1
1
  import {
2
2
  computeConfigHash,
3
3
  requestBuild
4
- } from "./chunk-TAQV6ZOB.js";
4
+ } from "./chunk-JGH5DCA7.js";
5
5
 
6
6
  // src/define-agent.ts
7
7
  function defineAgent(config) {
8
+ const catalogPrompt = config.catalog?.prompt({ mode: "inline" });
9
+ const agentMd = [config.agentMd, catalogPrompt].filter(Boolean).join("\n\n");
8
10
  return {
9
11
  agentType: config.agentType ?? "gemini",
10
- agentMd: config.agentMd,
12
+ agentMd: agentMd || void 0,
13
+ catalog: config.catalog,
11
14
  files: config.files ?? [],
15
+ env: config.env ? Object.fromEntries(
16
+ Object.entries(config.env).filter(
17
+ (entry) => entry[1] != null
18
+ )
19
+ ) : {},
20
+ setup: config.setup,
12
21
  get snapshotId() {
13
22
  const id = process.env?.GISELLE_AGENT_SNAPSHOT_ID;
14
23
  if (!id) {
@@ -1,5 +1,5 @@
1
1
  import { NextConfig } from 'next';
2
- import { A as AgentConfig } from '../types-Cto-uejG.js';
2
+ import { A as AgentConfig } from '../types-Co_KfALw.js';
3
3
 
4
4
  type GiselleAgentPluginOptions = {
5
5
  /** Base URL for the agent API. Default: process.env.GISELLE_AGENT_BASE_URL ?? "https://studio.giselles.ai/agent-api" */
@@ -1,9 +1,9 @@
1
1
  import {
2
+ computeConfigHash,
2
3
  requestBuild
3
- } from "../chunk-TAQV6ZOB.js";
4
+ } from "../chunk-JGH5DCA7.js";
4
5
 
5
6
  // src/next/with-giselle-agent.ts
6
- import crypto from "crypto";
7
7
  import fs from "fs";
8
8
  import { createRequire } from "module";
9
9
  import path from "path";
@@ -18,12 +18,7 @@ function resolveBaseUrl(options) {
18
18
  return (options?.baseUrl ?? process.env.GISELLE_AGENT_BASE_URL ?? "https://studio.giselles.ai/agent-api").replace(/\/+$/, "");
19
19
  }
20
20
  function getSnapshotFile(agent) {
21
- const key = {
22
- agentType: agent.agentType,
23
- agentMd: agent.agentMd,
24
- files: agent.files
25
- };
26
- const hash = crypto.createHash("sha256").update(JSON.stringify(key)).digest("hex").slice(0, 16);
21
+ const hash = computeConfigHash(agent);
27
22
  return path.join(process.cwd(), ".next", "giselle", hash);
28
23
  }
29
24
  function hasRunRecently() {
@@ -147,6 +147,7 @@ declare const cloudChatRunRequestSchema: z.ZodObject<{
147
147
  gemini: "gemini";
148
148
  }>;
149
149
  snapshot_id: z.ZodString;
150
+ env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
150
151
  tool_results: z.ZodOptional<z.ZodArray<z.ZodObject<{
151
152
  toolCallId: z.ZodString;
152
153
  toolName: z.ZodEnum<{
@@ -51,6 +51,8 @@ function parseBuildRequest(body) {
51
51
  const configHash = record.config_hash;
52
52
  const agentType = record.agent_type;
53
53
  const files = record.files;
54
+ const setupScript = record.setup_script;
55
+ const rawEnv = record.env;
54
56
  if (typeof configHash !== "string" || !configHash.trim()) {
55
57
  return null;
56
58
  }
@@ -61,6 +63,8 @@ function parseBuildRequest(body) {
61
63
  return null;
62
64
  }
63
65
  const parsedFiles = [];
66
+ let parsedSetupScript = null;
67
+ let parsedEnv = null;
64
68
  for (const file of files) {
65
69
  if (!file || typeof file !== "object" || Array.isArray(file)) {
66
70
  return null;
@@ -74,10 +78,30 @@ function parseBuildRequest(body) {
74
78
  content: recordFile.content
75
79
  });
76
80
  }
81
+ if (setupScript !== void 0 && setupScript !== null) {
82
+ if (typeof setupScript !== "string") {
83
+ return null;
84
+ }
85
+ parsedSetupScript = setupScript;
86
+ }
87
+ if (rawEnv !== void 0 && rawEnv !== null) {
88
+ if (typeof rawEnv !== "object" || Array.isArray(rawEnv)) {
89
+ return null;
90
+ }
91
+ const envRecord = rawEnv;
92
+ for (const value of Object.values(envRecord)) {
93
+ if (typeof value !== "string") {
94
+ return null;
95
+ }
96
+ }
97
+ parsedEnv = envRecord;
98
+ }
77
99
  return {
78
100
  config_hash: configHash.trim(),
79
101
  agent_type: agentType,
80
- files: parsedFiles
102
+ files: parsedFiles,
103
+ setup_script: parsedSetupScript,
104
+ env: parsedEnv
81
105
  };
82
106
  }
83
107
  async function buildAgent(input) {
@@ -123,6 +147,21 @@ async function buildAgent(input) {
123
147
  }))
124
148
  );
125
149
  }
150
+ if (parsed.setup_script) {
151
+ console.log("[agent-build] running setup script...");
152
+ const result = await sandbox.runCommand({
153
+ cmd: "bash",
154
+ args: ["-lc", parsed.setup_script],
155
+ ...parsed.env ? { env: parsed.env } : {}
156
+ });
157
+ if (result.exitCode !== 0) {
158
+ const stderr = typeof result.stderr === "string" ? result.stderr : "";
159
+ throw new Error(
160
+ `Setup script failed (exit ${result.exitCode}): ${stderr}`
161
+ );
162
+ }
163
+ console.log("[agent-build] setup script completed");
164
+ }
126
165
  const snapshot = await sandbox.snapshot();
127
166
  console.log(`[agent-build] snapshot created: ${snapshot.snapshotId}`);
128
167
  await cache.set(cacheKey, snapshot.snapshotId);
@@ -359,7 +398,12 @@ function createCodexAgent(options = {}) {
359
398
  return {
360
399
  cmd: "codex",
361
400
  args,
362
- env: { CODEX_API_KEY: apiKey }
401
+ env: Object.fromEntries(
402
+ Object.entries({
403
+ ...env,
404
+ CODEX_API_KEY: apiKey
405
+ }).filter((e) => e[1] != null)
406
+ )
363
407
  };
364
408
  },
365
409
  createStdoutMapper() {
@@ -493,17 +537,28 @@ function createGeminiAgent(options = {}) {
493
537
  "--output-format",
494
538
  "stream-json",
495
539
  "--approval-mode",
496
- "yolo"
540
+ "yolo",
541
+ "--sandbox",
542
+ "false"
497
543
  ];
498
544
  if (input.session_id) {
499
545
  args.push("--resume", input.session_id);
500
546
  }
547
+ console.info("[gemini-agent] createCommand", {
548
+ hasSessionId: Boolean(input.session_id),
549
+ hasSandboxId: Boolean(input.sandbox_id),
550
+ hasSnapshotId: Boolean(input.snapshot_id),
551
+ argCount: args.length
552
+ });
501
553
  return {
502
554
  cmd: "gemini",
503
555
  args,
504
- env: {
505
- GEMINI_API_KEY: requiredEnv2(env, "GEMINI_API_KEY")
506
- }
556
+ env: Object.fromEntries(
557
+ Object.entries({
558
+ ...env,
559
+ GEMINI_API_KEY: requiredEnv2(env, "GEMINI_API_KEY")
560
+ }).filter((e) => e[1] != null)
561
+ )
507
562
  };
508
563
  }
509
564
  };
@@ -550,6 +605,7 @@ function createAgent(options) {
550
605
  // src/chat-run.ts
551
606
  import { Writable } from "stream";
552
607
  import { Sandbox as Sandbox2 } from "@vercel/sandbox";
608
+ var COMMAND_TIMEOUT_EXTENSION_MS = 5 * 60 * 1e3;
553
609
  function emitText(controller, text, encoder) {
554
610
  if (text.length === 0) {
555
611
  return;
@@ -619,7 +675,21 @@ function runChat(input) {
619
675
  const sandbox = await (async () => {
620
676
  if (parsed.sandbox_id) {
621
677
  try {
622
- return await Sandbox2.get({ sandboxId: parsed.sandbox_id });
678
+ const existing = await Sandbox2.get({
679
+ sandboxId: parsed.sandbox_id
680
+ });
681
+ if (existing.status !== "running") {
682
+ if (!snapshotId) {
683
+ throw new Error(
684
+ `Sandbox ${parsed.sandbox_id} is ${existing.status}, not running`
685
+ );
686
+ }
687
+ console.log(
688
+ `[sandbox] sandbox=${parsed.sandbox_id} status=${existing.status}, recreating from snapshot=${snapshotId}`
689
+ );
690
+ return createFromSnapshot(snapshotId);
691
+ }
692
+ return existing;
623
693
  } catch (error) {
624
694
  if (!snapshotId) {
625
695
  throw error;
@@ -645,6 +715,16 @@ function runChat(input) {
645
715
  const command = input.agent.createCommand({
646
716
  input: parsed
647
717
  });
718
+ console.info("[chat-run] starting sandbox command", {
719
+ sandboxId: sandbox.sandboxId,
720
+ cmd: command.cmd,
721
+ args: command.args,
722
+ envKeys: Object.keys(command.env ?? {}).sort(),
723
+ hasSessionId: typeof parsed.session_id === "string" && parsed.session_id.length > 0,
724
+ hasSandboxId: typeof parsed.sandbox_id === "string" && parsed.sandbox_id.length > 0,
725
+ hasSnapshotId: typeof parsed.snapshot_id === "string" && parsed.snapshot_id.length > 0
726
+ });
727
+ await sandbox.extendTimeout(COMMAND_TIMEOUT_EXTENSION_MS);
648
728
  await sandbox.runCommand({
649
729
  cmd: command.cmd,
650
730
  args: command.args,
@@ -666,6 +746,10 @@ function runChat(input) {
666
746
  stderr: new Writable({
667
747
  write(chunk, _encoding, callback) {
668
748
  const text = typeof chunk === "string" ? chunk : chunk.toString("utf8");
749
+ console.error("[chat-run] sandbox stderr", {
750
+ sandboxId: sandbox.sandboxId,
751
+ content: text
752
+ });
669
753
  enqueueEvent({ type: "stderr", content: text });
670
754
  callback();
671
755
  }
@@ -822,6 +906,7 @@ var cloudChatRunRequestSchema = z3.object({
822
906
  message: z3.string().min(1),
823
907
  agent_type: z3.enum(["gemini", "codex"]),
824
908
  snapshot_id: z3.string().min(1),
909
+ env: z3.record(z3.string(), z3.string()).optional(),
825
910
  tool_results: z3.array(
826
911
  z3.object({
827
912
  toolCallId: z3.string().min(1),
@@ -921,8 +1006,12 @@ function injectRelayUrl(agent, relayUrl) {
921
1006
  }
922
1007
  };
923
1008
  }
1009
+ function usesBrowserTool(agent) {
1010
+ return isCreateAgentOptions2(agent) && agent.tools?.browser !== void 0;
1011
+ }
924
1012
  async function runCloudChat(input) {
925
- const agentParam = injectRelayUrl(input.agent, input.relayUrl);
1013
+ const browserToolEnabled = usesBrowserTool(input.agent);
1014
+ const agentParam = browserToolEnabled ? injectRelayUrl(input.agent, input.relayUrl) : input.agent;
926
1015
  const agent = resolveAgent(agentParam);
927
1016
  const now = input.now?.() ?? Date.now();
928
1017
  const createRelaySub = input.createRelayRequestSubscription ?? createRelayRequestSubscription;
@@ -944,23 +1033,29 @@ async function runCloudChat(input) {
944
1033
  sendResponse
945
1034
  });
946
1035
  }
947
- const relaySession = await input.createRelaySession();
948
- const relaySubscription = await createRelaySub({
949
- sessionId: relaySession.sessionId,
950
- token: relaySession.token
951
- });
952
- console.info("[cloud-chat] relay subscription ready", {
953
- chatId: input.chatId,
954
- relaySessionId: relaySession.sessionId
955
- });
956
1036
  const runtimeInput = {
957
1037
  ...input.request,
958
1038
  ...existing?.agentSessionId ? { session_id: existing.agentSessionId } : {},
959
1039
  ...existing?.sandboxId ? { sandbox_id: existing.sandboxId } : {},
960
- ...existing?.snapshotId ? { snapshot_id: existing.snapshotId } : {},
961
- relay_session_id: relaySession.sessionId,
962
- relay_token: relaySession.token
1040
+ ...existing?.snapshotId ? { snapshot_id: existing.snapshotId } : {}
963
1041
  };
1042
+ let relaySession;
1043
+ let relaySubscription = null;
1044
+ if (browserToolEnabled) {
1045
+ relaySession = await input.createRelaySession();
1046
+ relaySubscription = await createRelaySub({
1047
+ sessionId: relaySession.sessionId,
1048
+ token: relaySession.token
1049
+ });
1050
+ console.info("[cloud-chat] relay subscription ready", {
1051
+ chatId: input.chatId,
1052
+ relaySessionId: relaySession.sessionId
1053
+ });
1054
+ Object.assign(runtimeInput, {
1055
+ relay_session_id: relaySession.sessionId,
1056
+ relay_token: relaySession.token
1057
+ });
1058
+ }
964
1059
  let response;
965
1060
  try {
966
1061
  response = await (input.runChatImpl ?? runChat)({
@@ -969,7 +1064,7 @@ async function runCloudChat(input) {
969
1064
  input: runtimeInput
970
1065
  });
971
1066
  } catch (error) {
972
- await relaySubscription.close().catch(() => void 0);
1067
+ await relaySubscription?.close().catch(() => void 0);
973
1068
  throw error;
974
1069
  }
975
1070
  const managed = createManagedCloudResponseFromReader({
@@ -984,7 +1079,7 @@ async function runCloudChat(input) {
984
1079
  relaySubscription,
985
1080
  relaySession,
986
1081
  relayUrl: input.relayUrl,
987
- includeRelaySessionPrelude: true,
1082
+ includeRelaySessionPrelude: browserToolEnabled,
988
1083
  initialBuffer: "",
989
1084
  initialTextBlockOpen: false
990
1085
  });
@@ -1446,12 +1541,17 @@ function createAgentApi(options) {
1446
1541
  chat_id: parsed.data.chat_id,
1447
1542
  agent_type: parsed.data.agent_type,
1448
1543
  snapshot_id: parsed.data.snapshot_id,
1544
+ env: parsed.data.env,
1449
1545
  tool_results: parsed.data.tool_results
1450
1546
  },
1451
1547
  agent: {
1452
1548
  ...agentOptions,
1453
1549
  type: parsed.data.agent_type,
1454
- snapshotId: parsed.data.snapshot_id
1550
+ snapshotId: parsed.data.snapshot_id,
1551
+ env: {
1552
+ ...parsed.data.env,
1553
+ ...agentOptions.env
1554
+ }
1455
1555
  },
1456
1556
  signal: request.signal,
1457
1557
  store: await getStore(),
@@ -0,0 +1,43 @@
1
+ /** Minimal interface for a json-render catalog. */
2
+ type UICatalog = {
3
+ prompt(options?: {
4
+ mode?: "inline" | "standalone";
5
+ customRules?: string[];
6
+ }): string;
7
+ };
8
+ type AgentFile = {
9
+ path: string;
10
+ content: string;
11
+ };
12
+ type AgentSetup = {
13
+ /** Shell script to run inside the sandbox during build. Executed as `bash -lc`. */
14
+ script: string;
15
+ };
16
+ type AgentConfig = {
17
+ /** Agent type. Defaults to "gemini". */
18
+ agentType?: "gemini" | "codex";
19
+ /** Content for AGENTS.md in the sandbox. */
20
+ agentMd?: string;
21
+ /** Optional json-render catalog for generative UI. */
22
+ catalog?: UICatalog;
23
+ /** Environment variables passed to the sandbox at build and run time. */
24
+ env?: Record<string, string | undefined>;
25
+ /** Additional files to write into the sandbox. */
26
+ files?: AgentFile[];
27
+ /** Setup configuration for the sandbox build phase. */
28
+ setup?: AgentSetup;
29
+ };
30
+ type DefinedAgent = {
31
+ readonly agentType: "gemini" | "codex";
32
+ readonly agentMd?: string;
33
+ readonly catalog?: UICatalog;
34
+ readonly files: AgentFile[];
35
+ /** Setup configuration. Undefined when no setup is configured. */
36
+ readonly setup?: AgentSetup;
37
+ /** Environment variables. */
38
+ readonly env: Record<string, string>;
39
+ /** Snapshot ID resolved from env at runtime. Throws if not set. */
40
+ readonly snapshotId: string;
41
+ };
42
+
43
+ export type { AgentConfig as A, DefinedAgent as D, UICatalog as U, AgentFile as a, AgentSetup as b };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@giselles-ai/agent",
3
- "version": "0.1.24",
3
+ "version": "0.1.26",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "license": "Apache-2.0",
@@ -37,8 +37,9 @@
37
37
  "format": "pnpm exec biome check --write ."
38
38
  },
39
39
  "dependencies": {
40
- "@giselles-ai/browser-tool": "0.1.24",
41
- "@vercel/sandbox": "1.6.0",
40
+ "@giselles-ai/browser-tool": "0.1.26",
41
+ "@json-render/core": "0.13.0",
42
+ "@vercel/sandbox": "1.8.1",
42
43
  "@iarna/toml": "3.0.0",
43
44
  "zod": "4.3.6"
44
45
  },
@@ -1,21 +0,0 @@
1
- type AgentFile = {
2
- path: string;
3
- content: string;
4
- };
5
- type AgentConfig = {
6
- /** Agent type. Defaults to "gemini". */
7
- agentType?: "gemini" | "codex";
8
- /** Content for AGENTS.md in the sandbox. */
9
- agentMd?: string;
10
- /** Additional files to write into the sandbox. */
11
- files?: AgentFile[];
12
- };
13
- type DefinedAgent = {
14
- readonly agentType: "gemini" | "codex";
15
- readonly agentMd?: string;
16
- readonly files: AgentFile[];
17
- /** Snapshot ID resolved from env at runtime. Throws if not set. */
18
- readonly snapshotId: string;
19
- };
20
-
21
- export type { AgentConfig as A, DefinedAgent as D, AgentFile as a };