@womp/spark-agent 2.2.0 → 3.0.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.
package/dist/geometry.js CHANGED
@@ -7,11 +7,11 @@ export { migrateParameterOverrides, readParameterOverrides, } from "./geometry/p
7
7
  let reference;
8
8
  export function geometryReference() {
9
9
  reference ??= {
10
- rules: `Write one statement per line:
11
- param Float width = 20.0 min=1 max=100 step=1
12
- node box Primitive Type=Box Position=Vec3(0.0,0.0,0.0) Rotation=Vec3(0.0,0.0,0.0) Size=width Roundness=0.0
13
- out Geometry=box.Geometry
14
- Use decimal components in Vec3 parameter/constant literals, e.g. Vec3(20.0,20.0,20.0). Output name is case-sensitive: Geometry.
10
+ rules: `Write one statement per line:
11
+ param Float width = 20.0 min=1 max=100 step=1
12
+ node box Primitive Type=Box Position=Vec3(0.0,0.0,0.0) Rotation=Vec3(0.0,0.0,0.0) Size=width Roundness=0.0
13
+ out Geometry=box.Geometry
14
+ Use decimal components in Vec3 parameter/constant literals, e.g. Vec3(20.0,20.0,20.0). Output name is case-sensitive: Geometry.
15
15
  ${flowir.renderDslRulesBlock()}`,
16
16
  catalog: flowir.renderSchemaBlock(flowirRegistry.getSchema()),
17
17
  };
@@ -2,6 +2,13 @@ import { resolveReasoningEffort } from "./models.js";
2
2
  /** Standalone provider policy; browser hosts supply their own deployed model settings. */
3
3
  export function sparkModelOptions(modelId, provider, effort) {
4
4
  const reasoningEffort = resolveReasoningEffort(modelId, effort);
5
+ if (provider === "google") {
6
+ return {
7
+ google: {
8
+ thinkingConfig: { thinkingLevel: reasoningEffort, includeThoughts: true },
9
+ },
10
+ };
11
+ }
5
12
  if (provider === "anthropic") {
6
13
  return {
7
14
  anthropic: {
package/dist/models.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export type ModelProvider = "openai" | "anthropic";
1
+ export type ModelProvider = "openai" | "anthropic" | "google";
2
2
  export type ReasoningEffort = "low" | "medium" | "high" | "xhigh" | "max";
3
3
  export declare const REASONING_EFFORT_LABELS: Record<ReasoningEffort, string>;
4
4
  export type SparkModel = {
@@ -14,6 +14,18 @@ export declare const SPARK_MODELS: readonly [{
14
14
  readonly note: "Best OpenAI quality";
15
15
  readonly provider: "openai";
16
16
  readonly reasoningEfforts: readonly ["low", "medium", "high", "xhigh", "max"];
17
+ }, {
18
+ readonly id: "gpt-5.6-luna";
19
+ readonly label: "GPT-5.6 Luna";
20
+ readonly note: "Fast, cost-efficient OpenAI model";
21
+ readonly provider: "openai";
22
+ readonly reasoningEfforts: readonly ["low", "medium", "high", "xhigh", "max"];
23
+ }, {
24
+ readonly id: "gemini-3.8-flash";
25
+ readonly label: "Gemini 3.8 Flash";
26
+ readonly note: "Fast Google model";
27
+ readonly provider: "google";
28
+ readonly reasoningEfforts: readonly ["low", "medium", "high"];
17
29
  }, {
18
30
  readonly id: "claude-opus-5";
19
31
  readonly label: "Opus 5";
package/dist/models.js CHANGED
@@ -20,6 +20,20 @@ export const SPARK_MODELS = [
20
20
  provider: "openai",
21
21
  reasoningEfforts: EXTENDED_REASONING_EFFORTS,
22
22
  },
23
+ {
24
+ id: "gpt-5.6-luna",
25
+ label: "GPT-5.6 Luna",
26
+ note: "Fast, cost-efficient OpenAI model",
27
+ provider: "openai",
28
+ reasoningEfforts: EXTENDED_REASONING_EFFORTS,
29
+ },
30
+ {
31
+ id: "gemini-3.8-flash",
32
+ label: "Gemini 3.8 Flash",
33
+ note: "Fast Google model",
34
+ provider: "google",
35
+ reasoningEfforts: ["low", "medium", "high"],
36
+ },
23
37
  {
24
38
  id: "claude-opus-5",
25
39
  label: "Opus 5",
package/dist/pricing.js CHANGED
@@ -1,5 +1,15 @@
1
1
  // Standard, global, direct API rates in USD per million tokens, checked 2026-09-09.
2
2
  const PRICES = {
3
+ "gpt-5.6-luna": {
4
+ input: 0.2, read: 0.02, write: 0.25, output: 1.2, longContext: 272_000,
5
+ source: "https://developers.openai.com/api/docs/models/gpt-5.6-luna",
6
+ pricingDate: "2026-09-12",
7
+ },
8
+ "gemini-3.8-flash": {
9
+ input: 0.75, read: 0.075, write: 0.75, output: 3.75,
10
+ source: "https://ai.google.dev/gemini-api/docs/pricing#gemini-3.8-flash",
11
+ pricingDate: "2026-09-12", validUntil: "2027-01-01",
12
+ },
3
13
  "gpt-6-astra": {
4
14
  input: 10, read: 1, write: 12.5, output: 50, longContext: 272_000,
5
15
  source: "https://developers.openai.com/api/docs/models/gpt-6-astra",
@@ -16,12 +26,15 @@ const PRICES = {
16
26
  export function calculateStepCost(modelId, usage) {
17
27
  const price = PRICES[modelId];
18
28
  const result = {
19
- modelId, pricingDate: "2026-09-09", source: price?.source,
29
+ modelId, pricingDate: price?.pricingDate ?? "2026-09-09", source: price?.source,
20
30
  totalUsd: null, lines: [],
21
31
  };
22
32
  const unavailable = (reason) => ({ ...result, reason });
23
33
  if (price === undefined)
24
34
  return unavailable("No verified pricing for this model.");
35
+ if (price.validUntil !== undefined && Date.now() >= Date.parse(price.validUntil)) {
36
+ return unavailable("Verified pricing has expired.");
37
+ }
25
38
  const input = usage.inputTokens;
26
39
  const output = usage.outputTokens;
27
40
  const read = usage.inputTokenDetails.cacheReadTokens;
@@ -11,4 +11,4 @@
11
11
  },
12
12
  "shaders": []
13
13
  }
14
- }
14
+ }
@@ -11,4 +11,4 @@
11
11
  },
12
12
  "shaders": []
13
13
  }
14
- }
14
+ }
@@ -17,28 +17,28 @@ export class SqliteSparkStore {
17
17
  this.database.close();
18
18
  throw new Error(`Unsupported Spark database version: ${version}`);
19
19
  }
20
- this.database.exec(`
21
- PRAGMA busy_timeout = 5000;
22
- PRAGMA journal_mode = WAL;
23
- PRAGMA synchronous = FULL;
24
- PRAGMA foreign_keys = ON;
25
- CREATE TABLE IF NOT EXISTS conversations (
26
- id TEXT PRIMARY KEY, owner_id TEXT NOT NULL, updated_at TEXT NOT NULL, data TEXT NOT NULL
27
- );
28
- CREATE INDEX IF NOT EXISTS conversation_owner ON conversations(owner_id, updated_at);
29
- CREATE TABLE IF NOT EXISTS runs (
30
- id TEXT PRIMARY KEY, conversation_id TEXT NOT NULL, data TEXT NOT NULL
31
- );
32
- CREATE TABLE IF NOT EXISTS chunks (
33
- run_id TEXT NOT NULL REFERENCES runs(id), sequence INTEGER NOT NULL, data TEXT NOT NULL,
34
- PRIMARY KEY (run_id, sequence)
35
- );
36
- CREATE TABLE IF NOT EXISTS artifacts (
37
- id TEXT PRIMARY KEY, owner_id TEXT NOT NULL, metadata TEXT NOT NULL, bytes BLOB NOT NULL
38
- );
39
- CREATE TABLE IF NOT EXISTS execution_owner (
40
- singleton INTEGER PRIMARY KEY CHECK (singleton = 1), pid INTEGER NOT NULL, token TEXT NOT NULL
41
- );
20
+ this.database.exec(`
21
+ PRAGMA busy_timeout = 5000;
22
+ PRAGMA journal_mode = WAL;
23
+ PRAGMA synchronous = FULL;
24
+ PRAGMA foreign_keys = ON;
25
+ CREATE TABLE IF NOT EXISTS conversations (
26
+ id TEXT PRIMARY KEY, owner_id TEXT NOT NULL, updated_at TEXT NOT NULL, data TEXT NOT NULL
27
+ );
28
+ CREATE INDEX IF NOT EXISTS conversation_owner ON conversations(owner_id, updated_at);
29
+ CREATE TABLE IF NOT EXISTS runs (
30
+ id TEXT PRIMARY KEY, conversation_id TEXT NOT NULL, data TEXT NOT NULL
31
+ );
32
+ CREATE TABLE IF NOT EXISTS chunks (
33
+ run_id TEXT NOT NULL REFERENCES runs(id), sequence INTEGER NOT NULL, data TEXT NOT NULL,
34
+ PRIMARY KEY (run_id, sequence)
35
+ );
36
+ CREATE TABLE IF NOT EXISTS artifacts (
37
+ id TEXT PRIMARY KEY, owner_id TEXT NOT NULL, metadata TEXT NOT NULL, bytes BLOB NOT NULL
38
+ );
39
+ CREATE TABLE IF NOT EXISTS execution_owner (
40
+ singleton INTEGER PRIMARY KEY CHECK (singleton = 1), pid INTEGER NOT NULL, token TEXT NOT NULL
41
+ );
42
42
  CREATE TABLE IF NOT EXISTS scene_operations (
43
43
  target_key TEXT NOT NULL, id TEXT NOT NULL, revision INTEGER NOT NULL, data TEXT NOT NULL,
44
44
  PRIMARY KEY (target_key, id)
@@ -127,13 +127,13 @@ export class SqliteSparkStore {
127
127
  if (result.changes !== 1)
128
128
  throw new Error("Scene operation changed concurrently or is missing");
129
129
  if (next.status === "committed" || next.status === "rolled_back") {
130
- this.database.prepare(`
131
- DELETE FROM scene_operations WHERE rowid IN (
132
- SELECT rowid FROM scene_operations
133
- WHERE target_key = ? AND json_extract(data, '$.status') IN ('committed', 'rolled_back')
134
- ORDER BY COALESCE(json_extract(data, '$.completedAt'), '') DESC
135
- LIMIT -1 OFFSET ?
136
- )
130
+ this.database.prepare(`
131
+ DELETE FROM scene_operations WHERE rowid IN (
132
+ SELECT rowid FROM scene_operations
133
+ WHERE target_key = ? AND json_extract(data, '$.status') IN ('committed', 'rolled_back')
134
+ ORDER BY COALESCE(json_extract(data, '$.completedAt'), '') DESC
135
+ LIMIT -1 OFFSET ?
136
+ )
137
137
  `).run(next.targetKey, completedSceneOperationLimit);
138
138
  }
139
139
  this.database.exec("COMMIT");
@@ -3,6 +3,7 @@ import { KakapoAPI } from "@womp/kakapo-sdk";
3
3
  export type StandaloneSparkAgentOptions = {
4
4
  openAiApiKey?: string;
5
5
  anthropicApiKey?: string;
6
+ geminiApiKey?: string;
6
7
  kakapoUrl: string;
7
8
  apiBasePath?: string;
8
9
  developmentProfile?: "demo-account";
@@ -1,5 +1,6 @@
1
1
  import { createAnthropic } from "@ai-sdk/anthropic";
2
2
  import { createOpenAI } from "@ai-sdk/openai";
3
+ import { createGoogleGenerativeAI } from "@ai-sdk/google";
3
4
  import express from "express";
4
5
  import { getSparkModel, SPARK_MODELS } from "../models.js";
5
6
  import { KakapoAPI, KakapoRpcError } from "@womp/kakapo-sdk";
@@ -184,6 +185,17 @@ export async function createStandaloneSparkAgentApp(options) {
184
185
  maxOutputTokens: 48_000,
185
186
  };
186
187
  }
188
+ if (selected.provider === "google") {
189
+ if (!options.geminiApiKey?.trim()) {
190
+ throw new Error("GEMINI_API_KEY is required for this model.");
191
+ }
192
+ return {
193
+ model: createGoogleGenerativeAI({ apiKey: options.geminiApiKey })(selected.id),
194
+ modelId: selected.id,
195
+ providerOptions: sparkModelOptions(selected.id, selected.provider, settings.reasoningEffort),
196
+ maxOutputTokens: 48_000,
197
+ };
198
+ }
187
199
  if (options.openAiApiKey?.trim() === "" ||
188
200
  options.openAiApiKey === undefined) {
189
201
  throw new Error("OPENAI_API_KEY is required for this model.");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@womp/spark-agent",
3
- "version": "2.2.0",
3
+ "version": "3.0.0",
4
4
  "description": "Portable skills-based AI agent with local and durable chat transports for Womp",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -102,6 +102,7 @@
102
102
  },
103
103
  "dependencies": {
104
104
  "@ai-sdk/anthropic": "4.0.50",
105
+ "@ai-sdk/google": "4.0.69",
105
106
  "@ai-sdk/openai": "4.0.63",
106
107
  "@jitl/quickjs-wasmfile-release-sync": "0.32.0",
107
108
  "@womp/flowir": "0.3.0",