fix: Fix wasm tool schemas and runtime (#42)

* feat: Move debug log truncation from agent loop to REPL channel

Full tool output now flows through StatusUpdate so the web gateway
gets untruncated content. The REPL channel truncates at display time
(200 chars for tool results, thinking, and status messages).

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix: Flatten WASM tool schemas and fix host HTTP runtime contention

LLMs can't reliably follow oneOf + const discriminator patterns in JSON
Schema, causing tools like Google Calendar to receive malformed params
(e.g., {"operation":"list_events","data":{"calendarId":"primary"}} instead
of {"action":"list_events","calendar_id":"primary"}). Replace all 9 WASM
tool schemas with flat action enum + top-level properties. The serde
#[serde(tag = "action")] deserialization works identically.

Also fixes WASM host HTTP requests (channels and tools) stalling during
startup by replacing Handle::current().block_on() with a dedicated
single-threaded runtime per request, avoiding I/O driver contention.

Reduces verbose LLM debug logging (full request/response payloads) and
changes tower_http default from debug to warn.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* feat: Built-in OAuth credentials and combined Google scopes

Add infrastructure for shipping default OAuth credentials with the binary,
similar to how gcloud/rclone bake in their client_id. Credentials are set
at compile time via IRONCLAW_GOOGLE_CLIENT_ID / IRONCLAW_GOOGLE_CLIENT_SECRET
env vars, or can be hardcoded in src/cli/oauth_defaults.rs.

The fallback chain is: capabilities file > runtime env var > built-in defaults.

Also, when authing any Google tool, scopes from ALL installed Google tools
are now combined into a single OAuth request (they all share the same
google_oauth_token secret). One login covers Gmail, Calendar, Drive, etc.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* feat: Ship default Google OAuth credentials for zero-config auth

Google Desktop App credentials are not secret (per Google's own docs).
Hardcode them so `ironclaw tool auth <google-tool>` works out of the box
without requiring users to register their own OAuth app.

Credentials can still be overridden at compile time
(IRONCLAW_GOOGLE_CLIENT_ID) or runtime (GOOGLE_OAUTH_CLIENT_ID).

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix: Consistent OAuth callback port and polished landing page

- Use fixed port 9876 instead of scanning 9876-9886 (one redirect URI
  to register in provider OAuth apps, deterministic behavior)
- Replace broken unicode checkmark with SVG icons (charset was missing,
  rendered as mojibake)
- Dark themed landing page with proper card layout for both success
  and error states
- Add charset=utf-8 to Content-Type headers

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* refactor: Unify OAuth callback server across all auth flows

All three OAuth flows (WASM tool auth, MCP server auth, NEAR AI login)
now share the same code from cli::oauth_defaults:

- Fixed port 9876 (one redirect URI to register per provider)
- Shared landing page HTML (dark card with SVG icons, proper charset)
- Parameterized wait_for_callback(listener, path, param, display_name)

Removes ~120 lines of duplicated callback/HTML code.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* Support for oauth token refresh

* refactor: Replace bootstrap.json with ~/.ironclaw/.env for DATABASE_URL

Kill the 4-field BootstrapConfig JSON file. Only DATABASE_URL actually
needs disk persistence (chicken-and-egg before DB connect). The other
three fields are now derived: pool_size defaults to 10 via env var,
secrets master key is auto-detected (env then keychain probe), and
onboard_completed is inferred from DATABASE_URL presence.

The new format is a standard .env file loaded via dotenvy early in
main, so DATABASE_URL is available as a regular env var everywhere.

Handles three upgrade paths:
- Clean start: wizard writes .env, reload after wizard completes
- Returning user: .env loaded at startup, business as usual
- Legacy upgrade: bootstrap.json auto-migrated to .env on first run

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix: Address PR review findings

- Fix UTF-8 panic in truncate_for_preview (byte-slice on char boundary)
- Cap WASM guest timeout_ms at 5 minutes to prevent resource exhaustion
- Fix localhost detection in requires_auth() to avoid substring matches
  (e.g. "notlocalhost.com" no longer matches)
- Fix query param injection to insert before URL fragment
- Fix extract_host_from_url for IPv6 bracket notation
- Remove misleading schema defaults: Slack limit, Slides insertion_index,
  Docs index (per-action defaults documented in descriptions instead)

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* style: Fix cargo fmt formatting

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix: IPv6 loopback support for OAuth listener and localhost detection

- bind_callback_listener: try [::1] first, fall back to 127.0.0.1,
  so OAuth redirects work on systems where localhost resolves to ::1
- is_localhost_url: replace manual string parsing with url::Url for
  correct handling of IPv6 brackets, ports, userinfo, etc.
- Add url crate as direct dependency (already a transitive dep)

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix: Address PR review feedback on runtime reuse, onboard check, and OAuth binding

- Remove session file check from check_onboard_needed(); DATABASE_URL is sufficient
- Detect AddrInUse on IPv6 bind and fail immediately instead of falling through to IPv4
- Reuse dedicated tokio runtime across HTTP calls in both tool and channel WASM wrappers

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix: HTML-escape provider name in OAuth landing page, simplify Slack limit description

- Add html_escape() to prevent XSS in landing_html() where provider_name
  was interpolated directly into HTML (defense-in-depth, source is trusted
  but escaping costs nothing)
- Remove per-action default numbers from Slack limit field description to
  avoid confusing LLMs with conflicting defaults

Addresses review feedback from zmanian on PR #42.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix: Save all bootstrap fields from wizard, fix config module comment

- Wizard now saves secrets_master_key_source and database_pool_size to
  bootstrap.json (was only saving database_url and onboard_completed,
  which broke secrets after fresh onboard since SecretsConfig::resolve
  reads key source from bootstrap)
- Update config.rs module doc to reflect bootstrap.json priority chain
  instead of the removed ~/.ironclaw/.env approach

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* refactor: Replace BootstrapConfig with .env-based bootstrap

DATABASE_URL is the only setting that needs disk persistence before
the database is available. Instead of a custom bootstrap.json with 4
fields, use a standard ~/.ironclaw/.env file loaded via dotenvy.

- Remove BootstrapConfig struct entirely
- Restore ironclaw_env_path(), load_ironclaw_env(), save_database_url()
- SecretsConfig::resolve() now auto-detects (env var then keychain probe)
  instead of reading a saved source from bootstrap.json
- DatabaseConfig::resolve() reads DATABASE_URL from env only (dotenvy
  loads ~/.ironclaw/.env into the environment early in startup)
- check_onboard_needed() is now sync (just checks env vars)
- Wizard save_and_summarize() works for both postgres and libsql backends
- One-time migration from bootstrap.json to .env preserved

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix: Ensure load_ironclaw_env() runs in all Config paths, fix .env priority

- Config::from_env() and Config::from_db() now call load_ironclaw_env()
  internally (after dotenvy::dotenv()), so CLI commands like `memory`
  and `config` correctly load DATABASE_URL from ~/.ironclaw/.env
- Fix load order: standard ./.env first (higher priority), then
  ~/.ironclaw/.env, matching the documented priority chain
- Collapse nested if/if-let into let-chains (clippy::collapsible_if)
  in oauth_defaults.rs, tool.rs, and secrets/store.rs
- Fix rename_to_migrated to take &Path instead of &PathBuf

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix: Address PR review comments (quoting, SSRF, error mapping)

- Quote DATABASE_URL in .env writes so `#` in passwords isn't treated
  as a dotenv comment (e.g., `DATABASE_URL="postgres://..."`)
- Add SSRF defenses to refresh_oauth_token(): require HTTPS, reject
  private/loopback IPs (with DNS resolution), disable redirects.
  token_url comes from tool capabilities JSON, so a malicious tool
  could otherwise exfiltrate refresh tokens.
- Fix IPv4 bind error mapping: only map AddrInUse to PortInUse,
  use generic Io variant for other bind failures

Co-Authored-By: Claude Opus 4.6 <[email protected]>

---------

Co-authored-by: Claude Opus 4.6 <[email protected]>
This commit is contained in:
Illia Polosukhin
2026-02-14 21:21:22 +00:00
committed by GitHub
co-authored by Claude Opus 4.6
parent 408ae8a29a
commit a53b2c10b5
38 changed files with 2794 additions and 2301 deletions
+44 -107
View File
@@ -53,119 +53,56 @@ impl exports::near::agent::tool::Guest for GmailTool {
r#"{
"type": "object",
"required": ["action"],
"oneOf": [
{
"properties": {
"action": { "const": "list_messages" },
"query": {
"type": "string",
"description": "Gmail search query (same syntax as Gmail search box). Examples: 'is:unread', 'from:[email protected]', 'subject:meeting after:2025/01/01'"
},
"max_results": {
"type": "integer",
"description": "Maximum number of messages to return (default: 20)",
"default": 20
},
"label_ids": {
"type": "array",
"items": { "type": "string" },
"description": "Label IDs to filter by (e.g., 'INBOX', 'SENT', 'DRAFT')"
}
},
"required": ["action"]
"properties": {
"action": {
"type": "string",
"enum": ["list_messages", "get_message", "send_message", "create_draft", "reply_to_message", "trash_message"],
"description": "The Gmail operation to perform"
},
{
"properties": {
"action": { "const": "get_message" },
"message_id": {
"type": "string",
"description": "The message ID to retrieve"
}
},
"required": ["action", "message_id"]
"query": {
"type": "string",
"description": "Gmail search query (same syntax as Gmail search box, e.g., 'is:unread', 'from:[email protected]'). Used by: list_messages"
},
{
"properties": {
"action": { "const": "send_message" },
"to": {
"type": "string",
"description": "Recipient email address(es), comma-separated"
},
"subject": {
"type": "string",
"description": "Email subject"
},
"body": {
"type": "string",
"description": "Email body (plain text)"
},
"cc": {
"type": "string",
"description": "CC recipients, comma-separated"
},
"bcc": {
"type": "string",
"description": "BCC recipients, comma-separated"
}
},
"required": ["action", "to", "subject", "body"]
"max_results": {
"type": "integer",
"description": "Maximum number of messages to return (default: 20). Used by: list_messages",
"default": 20
},
{
"properties": {
"action": { "const": "create_draft" },
"to": {
"type": "string",
"description": "Recipient email address(es), comma-separated"
},
"subject": {
"type": "string",
"description": "Email subject"
},
"body": {
"type": "string",
"description": "Email body (plain text)"
},
"cc": {
"type": "string",
"description": "CC recipients, comma-separated"
},
"bcc": {
"type": "string",
"description": "BCC recipients, comma-separated"
}
},
"required": ["action", "to", "subject", "body"]
"label_ids": {
"type": "array",
"items": { "type": "string" },
"description": "Label IDs to filter by (e.g., 'INBOX', 'SENT', 'DRAFT'). Used by: list_messages"
},
{
"properties": {
"action": { "const": "reply_to_message" },
"message_id": {
"type": "string",
"description": "The message ID to reply to"
},
"body": {
"type": "string",
"description": "Reply body (plain text)"
},
"reply_all": {
"type": "boolean",
"description": "If true, reply to all recipients (default: false)",
"default": false
}
},
"required": ["action", "message_id", "body"]
"message_id": {
"type": "string",
"description": "Message ID. Required for: get_message, reply_to_message, trash_message"
},
{
"properties": {
"action": { "const": "trash_message" },
"message_id": {
"type": "string",
"description": "The message ID to move to trash"
}
},
"required": ["action", "message_id"]
"to": {
"type": "string",
"description": "Recipient email address(es), comma-separated. Required for: send_message, create_draft"
},
"subject": {
"type": "string",
"description": "Email subject. Required for: send_message, create_draft"
},
"body": {
"type": "string",
"description": "Email body (plain text). Required for: send_message, create_draft, reply_to_message"
},
"cc": {
"type": "string",
"description": "CC recipients, comma-separated. Used by: send_message, create_draft"
},
"bcc": {
"type": "string",
"description": "BCC recipients, comma-separated. Used by: send_message, create_draft"
},
"reply_all": {
"type": "boolean",
"description": "If true, reply to all recipients (default: false). Used by: reply_to_message",
"default": false
}
]
}
}"#
.to_string()
}
+65 -155
View File
@@ -52,166 +52,76 @@ impl exports::near::agent::tool::Guest for GoogleCalendarTool {
r#"{
"type": "object",
"required": ["action"],
"oneOf": [
{
"properties": {
"action": { "const": "list_events" },
"calendar_id": {
"type": "string",
"description": "Calendar ID (default: 'primary')",
"default": "primary"
},
"time_min": {
"type": "string",
"description": "Lower bound for event start time (RFC3339, e.g., '2025-01-15T00:00:00Z')"
},
"time_max": {
"type": "string",
"description": "Upper bound for event end time (RFC3339)"
},
"max_results": {
"type": "integer",
"description": "Maximum number of events to return (default: 25)",
"default": 25
},
"query": {
"type": "string",
"description": "Free text search terms to filter events"
}
},
"required": ["action"]
"properties": {
"action": {
"type": "string",
"enum": ["list_events", "get_event", "create_event", "update_event", "delete_event"],
"description": "The calendar operation to perform"
},
{
"properties": {
"action": { "const": "get_event" },
"calendar_id": {
"type": "string",
"description": "Calendar ID (default: 'primary')",
"default": "primary"
},
"event_id": {
"type": "string",
"description": "The event ID to retrieve"
}
},
"required": ["action", "event_id"]
"calendar_id": {
"type": "string",
"description": "Calendar ID (default: 'primary')",
"default": "primary"
},
{
"properties": {
"action": { "const": "create_event" },
"calendar_id": {
"type": "string",
"description": "Calendar ID (default: 'primary')",
"default": "primary"
},
"summary": {
"type": "string",
"description": "Event title"
},
"description": {
"type": "string",
"description": "Event description"
},
"location": {
"type": "string",
"description": "Event location"
},
"start_datetime": {
"type": "string",
"description": "Start time as RFC3339 (e.g., '2025-01-15T09:00:00-05:00'). Use start_date for all-day events."
},
"end_datetime": {
"type": "string",
"description": "End time as RFC3339. Use end_date for all-day events."
},
"start_date": {
"type": "string",
"description": "Start date for all-day events (e.g., '2025-01-15')"
},
"end_date": {
"type": "string",
"description": "End date for all-day events (exclusive, e.g., '2025-01-16' for a single day)"
},
"timezone": {
"type": "string",
"description": "Timezone (e.g., 'America/New_York')"
},
"attendees": {
"type": "array",
"items": { "type": "string" },
"description": "Attendee email addresses"
}
},
"required": ["action", "summary"]
"event_id": {
"type": "string",
"description": "Event ID. Required for: get_event, update_event, delete_event"
},
{
"properties": {
"action": { "const": "update_event" },
"calendar_id": {
"type": "string",
"description": "Calendar ID (default: 'primary')",
"default": "primary"
},
"event_id": {
"type": "string",
"description": "The event ID to update"
},
"summary": {
"type": "string",
"description": "New event title"
},
"description": {
"type": "string",
"description": "New event description"
},
"location": {
"type": "string",
"description": "New event location"
},
"start_datetime": {
"type": "string",
"description": "New start time (RFC3339)"
},
"end_datetime": {
"type": "string",
"description": "New end time (RFC3339)"
},
"start_date": {
"type": "string",
"description": "New start date for all-day events"
},
"end_date": {
"type": "string",
"description": "New end date for all-day events"
},
"timezone": {
"type": "string",
"description": "Timezone for datetime fields"
},
"attendees": {
"type": "array",
"items": { "type": "string" },
"description": "Replace attendees with these email addresses"
}
},
"required": ["action", "event_id"]
"time_min": {
"type": "string",
"description": "Lower bound for event start time (RFC3339, e.g., '2025-01-15T00:00:00Z'). Used by: list_events"
},
{
"properties": {
"action": { "const": "delete_event" },
"calendar_id": {
"type": "string",
"description": "Calendar ID (default: 'primary')",
"default": "primary"
},
"event_id": {
"type": "string",
"description": "The event ID to delete"
}
},
"required": ["action", "event_id"]
"time_max": {
"type": "string",
"description": "Upper bound for event end time (RFC3339). Used by: list_events"
},
"max_results": {
"type": "integer",
"description": "Maximum number of events to return (default: 25). Used by: list_events",
"default": 25
},
"query": {
"type": "string",
"description": "Free text search terms to filter events. Used by: list_events"
},
"summary": {
"type": "string",
"description": "Event title. Required for: create_event. Optional for: update_event"
},
"description": {
"type": "string",
"description": "Event description. Used by: create_event, update_event"
},
"location": {
"type": "string",
"description": "Event location. Used by: create_event, update_event"
},
"start_datetime": {
"type": "string",
"description": "Start time (RFC3339, e.g., '2025-01-15T09:00:00-05:00'). For all-day events use start_date. Used by: create_event, update_event"
},
"end_datetime": {
"type": "string",
"description": "End time (RFC3339). For all-day events use end_date. Used by: create_event, update_event"
},
"start_date": {
"type": "string",
"description": "Start date for all-day events (e.g., '2025-01-15'). Used by: create_event, update_event"
},
"end_date": {
"type": "string",
"description": "End date for all-day events (exclusive, e.g., '2025-01-16'). Used by: create_event, update_event"
},
"timezone": {
"type": "string",
"description": "Timezone (e.g., 'America/New_York'). Used by: create_event, update_event"
},
"attendees": {
"type": "array",
"items": { "type": "string" },
"description": "Attendee email addresses. Used by: create_event, update_event"
}
]
}
}"#
.to_string()
}
+103 -234
View File
@@ -74,251 +74,120 @@ impl exports::near::agent::tool::Guest for GoogleDocsTool {
r#"{
"type": "object",
"required": ["action"],
"oneOf": [
{
"properties": {
"action": { "const": "create_document" },
"title": {
"type": "string",
"description": "Document title"
}
},
"required": ["action", "title"]
"properties": {
"action": {
"type": "string",
"enum": ["create_document", "get_document", "read_content", "insert_text", "delete_content", "replace_text", "format_text", "format_paragraph", "insert_table", "create_list", "batch_update"],
"description": "The Google Docs operation to perform"
},
{
"properties": {
"action": { "const": "get_document" },
"document_id": {
"type": "string",
"description": "The document ID (same as Google Drive file ID)"
}
},
"required": ["action", "document_id"]
"title": {
"type": "string",
"description": "Document title. Required for: create_document"
},
{
"properties": {
"action": { "const": "read_content" },
"document_id": {
"type": "string",
"description": "The document ID"
}
},
"required": ["action", "document_id"]
"document_id": {
"type": "string",
"description": "The document ID (same as Google Drive file ID). Required for all actions except create_document"
},
{
"properties": {
"action": { "const": "insert_text" },
"document_id": {
"type": "string",
"description": "The document ID"
},
"text": {
"type": "string",
"description": "Text to insert"
},
"index": {
"type": "integer",
"description": "Character index to insert at (1 for start of body). Use -1 to append at end.",
"default": -1
},
"segment_id": {
"type": "string",
"description": "Segment ID (empty string for body, or a header/footer ID)",
"default": ""
}
},
"required": ["action", "document_id", "text"]
"text": {
"type": "string",
"description": "Text to insert. Required for: insert_text"
},
{
"properties": {
"action": { "const": "delete_content" },
"document_id": {
"type": "string",
"description": "The document ID"
},
"start_index": {
"type": "integer",
"description": "Start index (inclusive)"
},
"end_index": {
"type": "integer",
"description": "End index (exclusive)"
},
"segment_id": {
"type": "string",
"description": "Segment ID (empty for body)",
"default": ""
}
},
"required": ["action", "document_id", "start_index", "end_index"]
"index": {
"type": "integer",
"description": "Character index (1 for start of body, -1 to append at end). Required for: insert_table. Used by: insert_text (default: -1)"
},
{
"properties": {
"action": { "const": "replace_text" },
"document_id": {
"type": "string",
"description": "The document ID"
},
"find": {
"type": "string",
"description": "Text to search for"
},
"replace": {
"type": "string",
"description": "Replacement text"
},
"match_case": {
"type": "boolean",
"description": "Case-sensitive match (default: true)",
"default": true
}
},
"required": ["action", "document_id", "find", "replace"]
"segment_id": {
"type": "string",
"description": "Segment ID (empty for body, or a header/footer ID). Used by: insert_text, delete_content",
"default": ""
},
{
"properties": {
"action": { "const": "format_text" },
"document_id": {
"type": "string",
"description": "The document ID"
},
"start_index": {
"type": "integer",
"description": "Start index (inclusive)"
},
"end_index": {
"type": "integer",
"description": "End index (exclusive)"
},
"bold": {
"type": "boolean",
"description": "Make text bold"
},
"italic": {
"type": "boolean",
"description": "Make text italic"
},
"underline": {
"type": "boolean",
"description": "Underline text"
},
"strikethrough": {
"type": "boolean",
"description": "Strikethrough text"
},
"font_size": {
"type": "number",
"description": "Font size in points (e.g., 12, 14, 18)"
},
"font_family": {
"type": "string",
"description": "Font family (e.g., 'Arial', 'Times New Roman', 'Courier New')"
},
"foreground_color": {
"type": "string",
"description": "Text color as hex (e.g., '#FF0000' for red)"
},
"background_color": {
"type": "string",
"description": "Text background/highlight color as hex"
}
},
"required": ["action", "document_id", "start_index", "end_index"]
"start_index": {
"type": "integer",
"description": "Start index (inclusive). Required for: delete_content, format_text, format_paragraph, create_list"
},
{
"properties": {
"action": { "const": "format_paragraph" },
"document_id": {
"type": "string",
"description": "The document ID"
},
"start_index": {
"type": "integer",
"description": "Start index (inclusive)"
},
"end_index": {
"type": "integer",
"description": "End index (exclusive)"
},
"named_style": {
"type": "string",
"enum": ["NORMAL_TEXT", "TITLE", "SUBTITLE", "HEADING_1", "HEADING_2", "HEADING_3", "HEADING_4", "HEADING_5", "HEADING_6"],
"description": "Paragraph style (heading level)"
},
"alignment": {
"type": "string",
"enum": ["START", "CENTER", "END", "JUSTIFIED"],
"description": "Text alignment"
},
"line_spacing": {
"type": "number",
"description": "Line spacing as percentage (e.g., 100 for single, 150 for 1.5x, 200 for double)"
}
},
"required": ["action", "document_id", "start_index", "end_index"]
"end_index": {
"type": "integer",
"description": "End index (exclusive). Required for: delete_content, format_text, format_paragraph, create_list"
},
{
"properties": {
"action": { "const": "insert_table" },
"document_id": {
"type": "string",
"description": "The document ID"
},
"rows": {
"type": "integer",
"description": "Number of rows"
},
"columns": {
"type": "integer",
"description": "Number of columns"
},
"index": {
"type": "integer",
"description": "Character index to insert the table at"
}
},
"required": ["action", "document_id", "rows", "columns", "index"]
"find": {
"type": "string",
"description": "Text to search for. Required for: replace_text"
},
{
"properties": {
"action": { "const": "create_list" },
"document_id": {
"type": "string",
"description": "The document ID"
},
"start_index": {
"type": "integer",
"description": "Start index (inclusive)"
},
"end_index": {
"type": "integer",
"description": "End index (exclusive)"
},
"bullet_preset": {
"type": "string",
"enum": ["BULLET_DISC_CIRCLE_SQUARE", "BULLET_CHECKBOX", "BULLET_ARROW_DIAMOND_DISC", "NUMBERED_DECIMAL_ALPHA_ROMAN", "NUMBERED_DECIMAL_NESTED", "NUMBERED_UPPERALPHA_ALPHA_ROMAN"],
"description": "Bullet style preset (default: BULLET_DISC_CIRCLE_SQUARE)",
"default": "BULLET_DISC_CIRCLE_SQUARE"
}
},
"required": ["action", "document_id", "start_index", "end_index"]
"replace": {
"type": "string",
"description": "Replacement text. Required for: replace_text"
},
{
"properties": {
"action": { "const": "batch_update" },
"document_id": {
"type": "string",
"description": "The document ID"
},
"requests": {
"type": "array",
"items": { "type": "object" },
"description": "Array of raw Docs API batchUpdate request objects"
}
},
"required": ["action", "document_id", "requests"]
"match_case": {
"type": "boolean",
"description": "Case-sensitive match (default: true). Used by: replace_text",
"default": true
},
"bold": {
"type": "boolean",
"description": "Make text bold. Used by: format_text"
},
"italic": {
"type": "boolean",
"description": "Make text italic. Used by: format_text"
},
"underline": {
"type": "boolean",
"description": "Underline text. Used by: format_text"
},
"strikethrough": {
"type": "boolean",
"description": "Strikethrough text. Used by: format_text"
},
"font_size": {
"type": "number",
"description": "Font size in points (e.g., 12, 14, 18). Used by: format_text"
},
"font_family": {
"type": "string",
"description": "Font family (e.g., 'Arial', 'Times New Roman'). Used by: format_text"
},
"foreground_color": {
"type": "string",
"description": "Text color as hex (e.g., '#FF0000'). Used by: format_text"
},
"background_color": {
"type": "string",
"description": "Text background/highlight color as hex. Used by: format_text"
},
"named_style": {
"type": "string",
"enum": ["NORMAL_TEXT", "TITLE", "SUBTITLE", "HEADING_1", "HEADING_2", "HEADING_3", "HEADING_4", "HEADING_5", "HEADING_6"],
"description": "Paragraph style (heading level). Used by: format_paragraph"
},
"alignment": {
"type": "string",
"enum": ["START", "CENTER", "END", "JUSTIFIED"],
"description": "Text alignment. Used by: format_paragraph"
},
"line_spacing": {
"type": "number",
"description": "Line spacing as percentage (100=single, 150=1.5x, 200=double). Used by: format_paragraph"
},
"rows": {
"type": "integer",
"description": "Number of rows. Required for: insert_table"
},
"columns": {
"type": "integer",
"description": "Number of columns. Required for: insert_table"
},
"bullet_preset": {
"type": "string",
"enum": ["BULLET_DISC_CIRCLE_SQUARE", "BULLET_CHECKBOX", "BULLET_ARROW_DIAMOND_DISC", "NUMBERED_DECIMAL_ALPHA_ROMAN", "NUMBERED_DECIMAL_NESTED", "NUMBERED_UPPERALPHA_ALPHA_ROMAN"],
"description": "Bullet style preset (default: BULLET_DISC_CIRCLE_SQUARE). Used by: create_list",
"default": "BULLET_DISC_CIRCLE_SQUARE"
},
"requests": {
"type": "array",
"items": { "type": "object" },
"description": "Array of raw Docs API batchUpdate request objects. Required for: batch_update"
}
]
}
}"#
.to_string()
}
+77 -197
View File
@@ -62,215 +62,95 @@ impl exports::near::agent::tool::Guest for GoogleDriveTool {
r#"{
"type": "object",
"required": ["action"],
"oneOf": [
{
"properties": {
"action": { "const": "list_files" },
"query": {
"type": "string",
"description": "Drive search query. Examples: \"name contains 'report'\", \"mimeType = 'application/pdf'\", \"'folderId' in parents\", \"sharedWithMe = true\""
},
"page_size": {
"type": "integer",
"description": "Max results (default: 25, max: 1000)",
"default": 25
},
"order_by": {
"type": "string",
"description": "Sort order (e.g., 'modifiedTime desc', 'name')"
},
"corpora": {
"type": "string",
"enum": ["user", "drive", "domain", "allDrives"],
"description": "Search scope: 'user' (personal, default), 'drive' (specific shared drive), 'domain' (org-wide), 'allDrives' (everything)",
"default": "user"
},
"drive_id": {
"type": "string",
"description": "Shared drive ID (required when corpora is 'drive')"
},
"page_token": {
"type": "string",
"description": "Token for next page of results"
}
},
"required": ["action"]
"properties": {
"action": {
"type": "string",
"enum": ["list_files", "get_file", "download_file", "upload_file", "update_file", "create_folder", "delete_file", "trash_file", "share_file", "list_permissions", "remove_permission", "list_shared_drives"],
"description": "The Google Drive operation to perform"
},
{
"properties": {
"action": { "const": "get_file" },
"file_id": {
"type": "string",
"description": "The file ID"
}
},
"required": ["action", "file_id"]
"file_id": {
"type": "string",
"description": "File ID. Required for: get_file, download_file, update_file, delete_file, trash_file, share_file, list_permissions, remove_permission"
},
{
"properties": {
"action": { "const": "download_file" },
"file_id": {
"type": "string",
"description": "The file ID to download"
},
"export_mime_type": {
"type": "string",
"description": "Export format for Google Workspace files (e.g., 'text/plain', 'text/csv', 'application/pdf')"
}
},
"required": ["action", "file_id"]
"query": {
"type": "string",
"description": "Drive search query (e.g., \"name contains 'report'\", \"mimeType = 'application/pdf'\"). Used by: list_files"
},
{
"properties": {
"action": { "const": "upload_file" },
"name": {
"type": "string",
"description": "File name"
},
"content": {
"type": "string",
"description": "File content (text)"
},
"mime_type": {
"type": "string",
"description": "MIME type (default: 'text/plain')",
"default": "text/plain"
},
"parent_id": {
"type": "string",
"description": "Parent folder ID (omit for root)"
},
"description": {
"type": "string",
"description": "File description"
}
},
"required": ["action", "name", "content"]
"page_size": {
"type": "integer",
"description": "Max results (default: 25, max: 1000). Used by: list_files, list_shared_drives",
"default": 25
},
{
"properties": {
"action": { "const": "update_file" },
"file_id": {
"type": "string",
"description": "The file ID to update"
},
"name": {
"type": "string",
"description": "New file name"
},
"description": {
"type": "string",
"description": "New description"
},
"move_to_parent": {
"type": "string",
"description": "Move file to this folder ID"
},
"starred": {
"type": "boolean",
"description": "Star or unstar the file"
}
},
"required": ["action", "file_id"]
"order_by": {
"type": "string",
"description": "Sort order (e.g., 'modifiedTime desc', 'name'). Used by: list_files"
},
{
"properties": {
"action": { "const": "create_folder" },
"name": {
"type": "string",
"description": "Folder name"
},
"parent_id": {
"type": "string",
"description": "Parent folder ID (omit for root)"
},
"description": {
"type": "string",
"description": "Folder description"
}
},
"required": ["action", "name"]
"corpora": {
"type": "string",
"enum": ["user", "drive", "domain", "allDrives"],
"description": "Search scope: 'user' (default), 'drive' (shared drive), 'domain', 'allDrives'. Used by: list_files",
"default": "user"
},
{
"properties": {
"action": { "const": "delete_file" },
"file_id": {
"type": "string",
"description": "The file ID to permanently delete"
}
},
"required": ["action", "file_id"]
"drive_id": {
"type": "string",
"description": "Shared drive ID (required when corpora is 'drive'). Used by: list_files"
},
{
"properties": {
"action": { "const": "trash_file" },
"file_id": {
"type": "string",
"description": "The file ID to move to trash"
}
},
"required": ["action", "file_id"]
"page_token": {
"type": "string",
"description": "Token for next page of results. Used by: list_files"
},
{
"properties": {
"action": { "const": "share_file" },
"file_id": {
"type": "string",
"description": "The file ID to share"
},
"email": {
"type": "string",
"description": "Recipient email address"
},
"role": {
"type": "string",
"enum": ["reader", "commenter", "writer", "organizer"],
"description": "Permission level (default: 'reader')",
"default": "reader"
},
"message": {
"type": "string",
"description": "Optional message in sharing notification"
}
},
"required": ["action", "file_id", "email"]
"export_mime_type": {
"type": "string",
"description": "Export format for Google Workspace files (e.g., 'text/plain', 'text/csv'). Used by: download_file"
},
{
"properties": {
"action": { "const": "list_permissions" },
"file_id": {
"type": "string",
"description": "The file ID to check permissions for"
}
},
"required": ["action", "file_id"]
"name": {
"type": "string",
"description": "File/folder name. Required for: upload_file, create_folder. Optional for: update_file"
},
{
"properties": {
"action": { "const": "remove_permission" },
"file_id": {
"type": "string",
"description": "The file ID"
},
"permission_id": {
"type": "string",
"description": "The permission ID to remove (get from list_permissions)"
}
},
"required": ["action", "file_id", "permission_id"]
"content": {
"type": "string",
"description": "File content (text). Required for: upload_file"
},
{
"properties": {
"action": { "const": "list_shared_drives" },
"page_size": {
"type": "integer",
"description": "Max results (default: 25)",
"default": 25
}
},
"required": ["action"]
"mime_type": {
"type": "string",
"description": "MIME type (default: 'text/plain'). Used by: upload_file",
"default": "text/plain"
},
"parent_id": {
"type": "string",
"description": "Parent folder ID (omit for root). Used by: upload_file, create_folder"
},
"description": {
"type": "string",
"description": "File/folder description. Used by: upload_file, update_file, create_folder"
},
"move_to_parent": {
"type": "string",
"description": "Move file to this folder ID. Used by: update_file"
},
"starred": {
"type": "boolean",
"description": "Star or unstar the file. Used by: update_file"
},
"email": {
"type": "string",
"description": "Recipient email address. Required for: share_file"
},
"role": {
"type": "string",
"enum": ["reader", "commenter", "writer", "organizer"],
"description": "Permission level (default: 'reader'). Used by: share_file",
"default": "reader"
},
"message": {
"type": "string",
"description": "Optional message in sharing notification. Used by: share_file"
},
"permission_id": {
"type": "string",
"description": "Permission ID to remove (from list_permissions). Required for: remove_permission"
}
]
}
}"#
.to_string()
}
+83 -219
View File
@@ -70,236 +70,100 @@ impl exports::near::agent::tool::Guest for GoogleSheetsTool {
r#"{
"type": "object",
"required": ["action"],
"oneOf": [
{
"properties": {
"action": { "const": "create_spreadsheet" },
"title": {
"type": "string",
"description": "Spreadsheet title"
},
"sheet_names": {
"type": "array",
"items": { "type": "string" },
"description": "Names for sheets (tabs). Defaults to ['Sheet1'] if omitted."
}
},
"required": ["action", "title"]
"properties": {
"action": {
"type": "string",
"enum": ["create_spreadsheet", "get_spreadsheet", "read_values", "batch_read_values", "write_values", "append_values", "clear_values", "add_sheet", "delete_sheet", "rename_sheet", "format_cells"],
"description": "The Google Sheets operation to perform"
},
{
"properties": {
"action": { "const": "get_spreadsheet" },
"spreadsheet_id": {
"type": "string",
"description": "The spreadsheet ID (same as Google Drive file ID)"
}
},
"required": ["action", "spreadsheet_id"]
"spreadsheet_id": {
"type": "string",
"description": "Spreadsheet ID (same as Google Drive file ID). Required for all actions except create_spreadsheet"
},
{
"properties": {
"action": { "const": "read_values" },
"spreadsheet_id": {
"type": "string",
"description": "The spreadsheet ID"
},
"range": {
"type": "string",
"description": "A1 notation range (e.g., 'Sheet1!A1:D10', 'A1:B5')"
}
},
"required": ["action", "spreadsheet_id", "range"]
"title": {
"type": "string",
"description": "Title/name. Required for: create_spreadsheet, add_sheet, rename_sheet"
},
{
"properties": {
"action": { "const": "batch_read_values" },
"spreadsheet_id": {
"type": "string",
"description": "The spreadsheet ID"
},
"ranges": {
"type": "array",
"items": { "type": "string" },
"description": "List of A1 notation ranges to read"
}
},
"required": ["action", "spreadsheet_id", "ranges"]
"sheet_names": {
"type": "array",
"items": { "type": "string" },
"description": "Names for sheets (tabs, defaults to ['Sheet1']). Used by: create_spreadsheet"
},
{
"properties": {
"action": { "const": "write_values" },
"spreadsheet_id": {
"type": "string",
"description": "The spreadsheet ID"
},
"range": {
"type": "string",
"description": "A1 notation range (e.g., 'Sheet1!A1')"
},
"values": {
"type": "array",
"items": { "type": "array" },
"description": "2D array of values (rows of columns)"
},
"value_input_option": {
"type": "string",
"enum": ["RAW", "USER_ENTERED"],
"description": "How to interpret input. USER_ENTERED (default) parses like typing in the UI. RAW stores as-is.",
"default": "USER_ENTERED"
}
},
"required": ["action", "spreadsheet_id", "range", "values"]
"range": {
"type": "string",
"description": "A1 notation range (e.g., 'Sheet1!A1:D10'). Required for: read_values, write_values, append_values, clear_values"
},
{
"properties": {
"action": { "const": "append_values" },
"spreadsheet_id": {
"type": "string",
"description": "The spreadsheet ID"
},
"range": {
"type": "string",
"description": "A1 notation range to find the table (e.g., 'Sheet1!A:E')"
},
"values": {
"type": "array",
"items": { "type": "array" },
"description": "Rows to append (2D array)"
},
"value_input_option": {
"type": "string",
"enum": ["RAW", "USER_ENTERED"],
"description": "How to interpret input (default: USER_ENTERED)",
"default": "USER_ENTERED"
}
},
"required": ["action", "spreadsheet_id", "range", "values"]
"ranges": {
"type": "array",
"items": { "type": "string" },
"description": "List of A1 notation ranges. Required for: batch_read_values"
},
{
"properties": {
"action": { "const": "clear_values" },
"spreadsheet_id": {
"type": "string",
"description": "The spreadsheet ID"
},
"range": {
"type": "string",
"description": "A1 notation range to clear"
}
},
"required": ["action", "spreadsheet_id", "range"]
"values": {
"type": "array",
"items": { "type": "array" },
"description": "2D array of values (rows of columns). Required for: write_values, append_values"
},
{
"properties": {
"action": { "const": "add_sheet" },
"spreadsheet_id": {
"type": "string",
"description": "The spreadsheet ID"
},
"title": {
"type": "string",
"description": "Name for the new sheet (tab)"
}
},
"required": ["action", "spreadsheet_id", "title"]
"value_input_option": {
"type": "string",
"enum": ["RAW", "USER_ENTERED"],
"description": "How to interpret input (USER_ENTERED parses like the UI, RAW stores as-is, default: USER_ENTERED). Used by: write_values, append_values",
"default": "USER_ENTERED"
},
{
"properties": {
"action": { "const": "delete_sheet" },
"spreadsheet_id": {
"type": "string",
"description": "The spreadsheet ID"
},
"sheet_id": {
"type": "integer",
"description": "Numeric sheet ID (get from get_spreadsheet, NOT the sheet name)"
}
},
"required": ["action", "spreadsheet_id", "sheet_id"]
"sheet_id": {
"type": "integer",
"description": "Numeric sheet ID (from get_spreadsheet, NOT the sheet name). Required for: delete_sheet, rename_sheet, format_cells"
},
{
"properties": {
"action": { "const": "rename_sheet" },
"spreadsheet_id": {
"type": "string",
"description": "The spreadsheet ID"
},
"sheet_id": {
"type": "integer",
"description": "Numeric sheet ID"
},
"title": {
"type": "string",
"description": "New name for the sheet"
}
},
"required": ["action", "spreadsheet_id", "sheet_id", "title"]
"start_row": {
"type": "integer",
"description": "Start row (0-indexed, inclusive). Required for: format_cells"
},
{
"properties": {
"action": { "const": "format_cells" },
"spreadsheet_id": {
"type": "string",
"description": "The spreadsheet ID"
},
"sheet_id": {
"type": "integer",
"description": "Numeric sheet ID"
},
"start_row": {
"type": "integer",
"description": "Start row (0-indexed, inclusive)"
},
"end_row": {
"type": "integer",
"description": "End row (0-indexed, exclusive)"
},
"start_column": {
"type": "integer",
"description": "Start column (0-indexed, inclusive)"
},
"end_column": {
"type": "integer",
"description": "End column (0-indexed, exclusive)"
},
"bold": {
"type": "boolean",
"description": "Make text bold"
},
"italic": {
"type": "boolean",
"description": "Make text italic"
},
"font_size": {
"type": "integer",
"description": "Font size in points"
},
"text_color": {
"type": "string",
"description": "Text color as hex (e.g., '#FF0000' for red)"
},
"background_color": {
"type": "string",
"description": "Cell background color as hex (e.g., '#FFFF00' for yellow)"
},
"horizontal_alignment": {
"type": "string",
"enum": ["LEFT", "CENTER", "RIGHT"],
"description": "Horizontal text alignment"
},
"number_format": {
"type": "string",
"description": "Number format pattern (e.g., '#,##0.00', 'yyyy-mm-dd', '$#,##0')"
},
"number_format_type": {
"type": "string",
"enum": ["NUMBER", "CURRENCY", "PERCENT", "DATE", "TIME", "TEXT"],
"description": "Type of number format (default: NUMBER)"
}
},
"required": ["action", "spreadsheet_id", "sheet_id", "start_row", "end_row", "start_column", "end_column"]
"end_row": {
"type": "integer",
"description": "End row (0-indexed, exclusive). Required for: format_cells"
},
"start_column": {
"type": "integer",
"description": "Start column (0-indexed, inclusive). Required for: format_cells"
},
"end_column": {
"type": "integer",
"description": "End column (0-indexed, exclusive). Required for: format_cells"
},
"bold": {
"type": "boolean",
"description": "Make text bold. Used by: format_cells"
},
"italic": {
"type": "boolean",
"description": "Make text italic. Used by: format_cells"
},
"font_size": {
"type": "integer",
"description": "Font size in points. Used by: format_cells"
},
"text_color": {
"type": "string",
"description": "Text color as hex (e.g., '#FF0000'). Used by: format_cells"
},
"background_color": {
"type": "string",
"description": "Cell background color as hex (e.g., '#FFFF00'). Used by: format_cells"
},
"horizontal_alignment": {
"type": "string",
"enum": ["LEFT", "CENTER", "RIGHT"],
"description": "Horizontal text alignment. Used by: format_cells"
},
"number_format": {
"type": "string",
"description": "Number format pattern (e.g., '#,##0.00', 'yyyy-mm-dd'). Used by: format_cells"
},
"number_format_type": {
"type": "string",
"enum": ["NUMBER", "CURRENCY", "PERCENT", "DATE", "TIME", "TEXT"],
"description": "Type of number format (default: NUMBER). Used by: format_cells"
}
]
}
}"#
.to_string()
}
+104 -306
View File
@@ -79,326 +79,124 @@ impl exports::near::agent::tool::Guest for GoogleSlidesTool {
r#"{
"type": "object",
"required": ["action"],
"oneOf": [
{
"properties": {
"action": { "const": "create_presentation" },
"title": {
"type": "string",
"description": "Presentation title"
}
},
"required": ["action", "title"]
"properties": {
"action": {
"type": "string",
"enum": ["create_presentation", "get_presentation", "get_thumbnail", "create_slide", "delete_object", "insert_text", "delete_text", "replace_all_text", "create_shape", "insert_image", "format_text", "format_paragraph", "replace_shapes_with_image", "batch_update"],
"description": "The Google Slides operation to perform"
},
{
"properties": {
"action": { "const": "get_presentation" },
"presentation_id": {
"type": "string",
"description": "The presentation ID (same as Google Drive file ID)"
}
},
"required": ["action", "presentation_id"]
"title": {
"type": "string",
"description": "Presentation title. Required for: create_presentation"
},
{
"properties": {
"action": { "const": "get_thumbnail" },
"presentation_id": {
"type": "string",
"description": "The presentation ID"
},
"slide_object_id": {
"type": "string",
"description": "The slide's object ID"
}
},
"required": ["action", "presentation_id", "slide_object_id"]
"presentation_id": {
"type": "string",
"description": "Presentation ID (same as Google Drive file ID). Required for all actions except create_presentation"
},
{
"properties": {
"action": { "const": "create_slide" },
"presentation_id": {
"type": "string",
"description": "The presentation ID"
},
"insertion_index": {
"type": "integer",
"description": "Position to insert (0-based). Omit to append at end."
},
"layout": {
"type": "string",
"enum": ["BLANK", "TITLE", "TITLE_AND_BODY", "TITLE_AND_TWO_COLUMNS", "TITLE_ONLY", "SECTION_HEADER", "CAPTION_ONLY", "BIG_NUMBER", "ONE_COLUMN_TEXT", "MAIN_POINT"],
"description": "Predefined layout (default: BLANK)",
"default": "BLANK"
}
},
"required": ["action", "presentation_id"]
"slide_object_id": {
"type": "string",
"description": "Slide object ID. Required for: get_thumbnail, create_shape, insert_image"
},
{
"properties": {
"action": { "const": "delete_object" },
"presentation_id": {
"type": "string",
"description": "The presentation ID"
},
"object_id": {
"type": "string",
"description": "Object ID of the slide or element to delete"
}
},
"required": ["action", "presentation_id", "object_id"]
"object_id": {
"type": "string",
"description": "Object ID of a slide element. Required for: delete_object, insert_text, delete_text, format_text, format_paragraph"
},
{
"properties": {
"action": { "const": "insert_text" },
"presentation_id": {
"type": "string",
"description": "The presentation ID"
},
"object_id": {
"type": "string",
"description": "Object ID of the shape or text box"
},
"text": {
"type": "string",
"description": "Text to insert"
},
"insertion_index": {
"type": "integer",
"description": "Character index to insert at (0-based). Default: 0.",
"default": 0
}
},
"required": ["action", "presentation_id", "object_id", "text"]
"text": {
"type": "string",
"description": "Text to insert. Required for: insert_text"
},
{
"properties": {
"action": { "const": "delete_text" },
"presentation_id": {
"type": "string",
"description": "The presentation ID"
},
"object_id": {
"type": "string",
"description": "Object ID of the shape"
},
"start_index": {
"type": "integer",
"description": "Start index (inclusive, 0-based)",
"default": 0
},
"end_index": {
"type": "integer",
"description": "End index (exclusive). Omit to delete from start_index to end."
}
},
"required": ["action", "presentation_id", "object_id"]
"insertion_index": {
"type": "integer",
"description": "Position to insert at (0-based). Used by: create_slide (omit to append at end), insert_text (default: 0)"
},
{
"properties": {
"action": { "const": "replace_all_text" },
"presentation_id": {
"type": "string",
"description": "The presentation ID"
},
"find": {
"type": "string",
"description": "Text to search for"
},
"replace": {
"type": "string",
"description": "Replacement text"
},
"match_case": {
"type": "boolean",
"description": "Case-sensitive match (default: true)",
"default": true
}
},
"required": ["action", "presentation_id", "find", "replace"]
"layout": {
"type": "string",
"enum": ["BLANK", "TITLE", "TITLE_AND_BODY", "TITLE_AND_TWO_COLUMNS", "TITLE_ONLY", "SECTION_HEADER", "CAPTION_ONLY", "BIG_NUMBER", "ONE_COLUMN_TEXT", "MAIN_POINT"],
"description": "Predefined slide layout (default: BLANK). Used by: create_slide",
"default": "BLANK"
},
{
"properties": {
"action": { "const": "create_shape" },
"presentation_id": {
"type": "string",
"description": "The presentation ID"
},
"slide_object_id": {
"type": "string",
"description": "Slide object ID to place the shape on"
},
"shape_type": {
"type": "string",
"enum": ["TEXT_BOX", "RECTANGLE", "ROUND_RECTANGLE", "ELLIPSE"],
"description": "Shape type (default: TEXT_BOX)",
"default": "TEXT_BOX"
},
"x": {
"type": "number",
"description": "X position in points from left edge"
},
"y": {
"type": "number",
"description": "Y position in points from top edge"
},
"width": {
"type": "number",
"description": "Width in points"
},
"height": {
"type": "number",
"description": "Height in points"
}
},
"required": ["action", "presentation_id", "slide_object_id", "x", "y", "width", "height"]
"start_index": {
"type": "integer",
"description": "Start index (inclusive, 0-based). Used by: delete_text, format_text, format_paragraph"
},
{
"properties": {
"action": { "const": "insert_image" },
"presentation_id": {
"type": "string",
"description": "The presentation ID"
},
"slide_object_id": {
"type": "string",
"description": "Slide object ID to place the image on"
},
"image_url": {
"type": "string",
"description": "Publicly accessible image URL"
},
"x": {
"type": "number",
"description": "X position in points"
},
"y": {
"type": "number",
"description": "Y position in points"
},
"width": {
"type": "number",
"description": "Width in points"
},
"height": {
"type": "number",
"description": "Height in points"
}
},
"required": ["action", "presentation_id", "slide_object_id", "image_url", "x", "y", "width", "height"]
"end_index": {
"type": "integer",
"description": "End index (exclusive). Used by: delete_text, format_text, format_paragraph"
},
{
"properties": {
"action": { "const": "format_text" },
"presentation_id": {
"type": "string",
"description": "The presentation ID"
},
"object_id": {
"type": "string",
"description": "Object ID of the shape"
},
"start_index": {
"type": "integer",
"description": "Start index (inclusive). Omit to format all text."
},
"end_index": {
"type": "integer",
"description": "End index (exclusive). Omit to format to end."
},
"bold": {
"type": "boolean",
"description": "Make text bold"
},
"italic": {
"type": "boolean",
"description": "Make text italic"
},
"underline": {
"type": "boolean",
"description": "Underline text"
},
"font_size": {
"type": "number",
"description": "Font size in points (e.g., 12, 18, 24)"
},
"font_family": {
"type": "string",
"description": "Font family (e.g., 'Arial', 'Roboto', 'Times New Roman')"
},
"foreground_color": {
"type": "string",
"description": "Text color as hex (e.g., '#FF0000' for red)"
}
},
"required": ["action", "presentation_id", "object_id"]
"find": {
"type": "string",
"description": "Text to search for. Required for: replace_all_text, replace_shapes_with_image"
},
{
"properties": {
"action": { "const": "format_paragraph" },
"presentation_id": {
"type": "string",
"description": "The presentation ID"
},
"object_id": {
"type": "string",
"description": "Object ID of the shape"
},
"alignment": {
"type": "string",
"enum": ["START", "CENTER", "END", "JUSTIFIED"],
"description": "Paragraph alignment"
},
"start_index": {
"type": "integer",
"description": "Start index (inclusive). Omit to format all."
},
"end_index": {
"type": "integer",
"description": "End index (exclusive). Omit to format to end."
}
},
"required": ["action", "presentation_id", "object_id", "alignment"]
"replace": {
"type": "string",
"description": "Replacement text. Required for: replace_all_text"
},
{
"properties": {
"action": { "const": "replace_shapes_with_image" },
"presentation_id": {
"type": "string",
"description": "The presentation ID"
},
"find": {
"type": "string",
"description": "Text to match in shapes"
},
"image_url": {
"type": "string",
"description": "Image URL to replace matched shapes with"
},
"match_case": {
"type": "boolean",
"description": "Case-sensitive match (default: true)",
"default": true
}
},
"required": ["action", "presentation_id", "find", "image_url"]
"match_case": {
"type": "boolean",
"description": "Case-sensitive match (default: true). Used by: replace_all_text, replace_shapes_with_image",
"default": true
},
{
"properties": {
"action": { "const": "batch_update" },
"presentation_id": {
"type": "string",
"description": "The presentation ID"
},
"requests": {
"type": "array",
"items": { "type": "object" },
"description": "Array of raw Slides API batchUpdate request objects"
}
},
"required": ["action", "presentation_id", "requests"]
"shape_type": {
"type": "string",
"enum": ["TEXT_BOX", "RECTANGLE", "ROUND_RECTANGLE", "ELLIPSE"],
"description": "Shape type (default: TEXT_BOX). Used by: create_shape",
"default": "TEXT_BOX"
},
"x": {
"type": "number",
"description": "X position in points from left edge. Required for: create_shape, insert_image"
},
"y": {
"type": "number",
"description": "Y position in points from top edge. Required for: create_shape, insert_image"
},
"width": {
"type": "number",
"description": "Width in points. Required for: create_shape, insert_image"
},
"height": {
"type": "number",
"description": "Height in points. Required for: create_shape, insert_image"
},
"image_url": {
"type": "string",
"description": "Publicly accessible image URL. Required for: insert_image, replace_shapes_with_image"
},
"bold": {
"type": "boolean",
"description": "Make text bold. Used by: format_text"
},
"italic": {
"type": "boolean",
"description": "Make text italic. Used by: format_text"
},
"underline": {
"type": "boolean",
"description": "Underline text. Used by: format_text"
},
"font_size": {
"type": "number",
"description": "Font size in points (e.g., 12, 18, 24). Used by: format_text"
},
"font_family": {
"type": "string",
"description": "Font family (e.g., 'Arial', 'Roboto'). Used by: format_text"
},
"foreground_color": {
"type": "string",
"description": "Text color as hex (e.g., '#FF0000'). Used by: format_text"
},
"alignment": {
"type": "string",
"enum": ["START", "CENTER", "END", "JUSTIFIED"],
"description": "Paragraph alignment. Required for: format_paragraph"
},
"requests": {
"type": "array",
"items": { "type": "object" },
"description": "Array of raw Slides API batchUpdate request objects. Required for: batch_update"
}
]
}
}"#
.to_string()
}
+15 -46
View File
@@ -54,56 +54,25 @@ impl exports::near::agent::tool::Guest for OktaTool {
r#"{
"type": "object",
"required": ["action"],
"oneOf": [
{
"properties": {
"action": { "const": "get_profile" }
},
"required": ["action"]
"properties": {
"action": {
"type": "string",
"enum": ["get_profile", "update_profile", "list_apps", "search_apps", "get_app_sso_link", "get_org_info"],
"description": "The Okta operation to perform"
},
{
"properties": {
"action": { "const": "update_profile" },
"fields": {
"type": "object",
"description": "Profile fields to update. Common: firstName, lastName, email, mobilePhone, displayName, nickName, title, department, organization"
}
},
"required": ["action", "fields"]
"fields": {
"type": "object",
"description": "Profile fields to update (e.g., firstName, lastName, email, mobilePhone, displayName, title, department). Required for: update_profile"
},
{
"properties": {
"action": { "const": "list_apps" }
},
"required": ["action"]
"query": {
"type": "string",
"description": "Case-insensitive search query to match against app labels and names. Required for: search_apps"
},
{
"properties": {
"action": { "const": "search_apps" },
"query": {
"type": "string",
"description": "Case-insensitive search query to match against app labels and names"
}
},
"required": ["action", "query"]
},
{
"properties": {
"action": { "const": "get_app_sso_link" },
"app": {
"type": "string",
"description": "App instance ID (e.g., '0oa1xxx') or app label (e.g., 'Google Workspace')"
}
},
"required": ["action", "app"]
},
{
"properties": {
"action": { "const": "get_org_info" }
},
"required": ["action"]
"app": {
"type": "string",
"description": "App instance ID (e.g., '0oa1xxx') or app label (e.g., 'Google Workspace'). Required for: get_app_sso_link"
}
]
}
}"#
.to_string()
}
+30 -70
View File
@@ -53,84 +53,44 @@ impl exports::near::agent::tool::Guest for SlackTool {
}
fn schema() -> String {
// JSON Schema for the tool's parameters
r#"{
"type": "object",
"required": ["action"],
"oneOf": [
{
"properties": {
"action": { "const": "send_message" },
"channel": {
"type": "string",
"description": "Channel ID or name (e.g., '#general' or 'C1234567890')"
},
"text": {
"type": "string",
"description": "Message text (supports Slack mrkdwn formatting)"
},
"thread_ts": {
"type": "string",
"description": "Optional thread timestamp to reply in a thread"
}
},
"required": ["action", "channel", "text"]
"properties": {
"action": {
"type": "string",
"enum": ["send_message", "list_channels", "get_channel_history", "post_reaction", "get_user_info"],
"description": "The Slack operation to perform"
},
{
"properties": {
"action": { "const": "list_channels" },
"limit": {
"type": "integer",
"description": "Maximum number of channels to return (default: 100)",
"default": 100
}
},
"required": ["action"]
"channel": {
"type": "string",
"description": "Channel ID or name (e.g., '#general' or 'C1234567890'). Required for: send_message, get_channel_history, post_reaction"
},
{
"properties": {
"action": { "const": "get_channel_history" },
"channel": {
"type": "string",
"description": "Channel ID (e.g., 'C1234567890')"
},
"limit": {
"type": "integer",
"description": "Maximum number of messages to return (default: 20)",
"default": 20
}
},
"required": ["action", "channel"]
"text": {
"type": "string",
"description": "Message text (supports Slack mrkdwn formatting). Required for: send_message"
},
{
"properties": {
"action": { "const": "post_reaction" },
"channel": {
"type": "string",
"description": "Channel ID containing the message"
},
"timestamp": {
"type": "string",
"description": "Timestamp of the message to react to"
},
"emoji": {
"type": "string",
"description": "Emoji name without colons (e.g., 'thumbsup')"
}
},
"required": ["action", "channel", "timestamp", "emoji"]
"thread_ts": {
"type": "string",
"description": "Thread timestamp to reply in a thread. Used by: send_message"
},
{
"properties": {
"action": { "const": "get_user_info" },
"user_id": {
"type": "string",
"description": "User ID (e.g., 'U1234567890')"
}
},
"required": ["action", "user_id"]
"limit": {
"type": "integer",
"description": "Maximum number of results to return. Used by: list_channels, get_channel_history"
},
"timestamp": {
"type": "string",
"description": "Timestamp of the message to react to. Required for: post_reaction"
},
"emoji": {
"type": "string",
"description": "Emoji name without colons (e.g., 'thumbsup'). Required for: post_reaction"
},
"user_id": {
"type": "string",
"description": "User ID (e.g., 'U1234567890'). Required for: get_user_info"
}
]
}
}"#
.to_string()
}
+46 -136
View File
@@ -248,154 +248,64 @@ fn get_api_hash() -> Result<String, String> {
const SCHEMA: &str = r#"{
"type": "object",
"required": ["action"],
"oneOf": [
{
"properties": {
"action": { "const": "login" },
"phone_number": {
"type": "string",
"description": "Phone number in international format (e.g., '+1234567890')"
}
},
"required": ["action", "phone_number"]
"properties": {
"action": {
"type": "string",
"enum": ["login", "submit_auth_code", "submit_2fa_password", "get_me", "get_contacts", "get_chats", "get_messages", "send_message", "forward_message", "delete_message", "search_messages", "get_updates"],
"description": "The Telegram operation to perform"
},
{
"properties": {
"action": { "const": "submit_auth_code" },
"code": {
"type": "string",
"description": "Verification code received via SMS or Telegram"
}
},
"required": ["action", "code"]
"phone_number": {
"type": "string",
"description": "Phone number in international format (e.g., '+1234567890'). Required for: login"
},
{
"properties": {
"action": { "const": "submit_2fa_password" },
"password": {
"type": "string",
"description": "Two-factor authentication password"
}
},
"required": ["action", "password"]
"code": {
"type": "string",
"description": "Verification code received via SMS or Telegram. Required for: submit_auth_code"
},
{
"properties": {
"action": { "const": "get_me" }
},
"required": ["action"]
"password": {
"type": "string",
"description": "Two-factor authentication password. Required for: submit_2fa_password"
},
{
"properties": {
"action": { "const": "get_contacts" }
},
"required": ["action"]
"chat_id": {
"type": "integer",
"description": "Chat ID (negative for groups/channels). Required for: get_messages, send_message. Optional for: search_messages"
},
{
"properties": {
"action": { "const": "get_chats" },
"limit": {
"type": "integer",
"description": "Maximum number of chats to return (default: 20)",
"default": 20
}
},
"required": ["action"]
"limit": {
"type": "integer",
"description": "Maximum number of results (default: 20). Used by: get_chats, get_messages, search_messages",
"default": 20
},
{
"properties": {
"action": { "const": "get_messages" },
"chat_id": {
"type": "integer",
"description": "Chat ID (negative for groups/channels)"
},
"limit": {
"type": "integer",
"description": "Maximum number of messages (default: 20)",
"default": 20
},
"from_message_id": {
"type": "integer",
"description": "Start from this message ID for pagination"
}
},
"required": ["action", "chat_id"]
"from_message_id": {
"type": "integer",
"description": "Start from this message ID for pagination. Used by: get_messages"
},
{
"properties": {
"action": { "const": "send_message" },
"chat_id": {
"type": "integer",
"description": "Chat ID to send the message to"
},
"text": {
"type": "string",
"description": "Message text"
}
},
"required": ["action", "chat_id", "text"]
"text": {
"type": "string",
"description": "Message text. Required for: send_message"
},
{
"properties": {
"action": { "const": "forward_message" },
"from_chat_id": {
"type": "integer",
"description": "Source chat ID"
},
"to_chat_id": {
"type": "integer",
"description": "Destination chat ID"
},
"message_ids": {
"type": "array",
"items": { "type": "integer" },
"description": "Message IDs to forward"
}
},
"required": ["action", "from_chat_id", "to_chat_id", "message_ids"]
"from_chat_id": {
"type": "integer",
"description": "Source chat ID. Required for: forward_message"
},
{
"properties": {
"action": { "const": "delete_message" },
"message_ids": {
"type": "array",
"items": { "type": "integer" },
"description": "Message IDs to delete"
},
"revoke": {
"type": "boolean",
"description": "Also delete for other participants (default: false)",
"default": false
}
},
"required": ["action", "message_ids"]
"to_chat_id": {
"type": "integer",
"description": "Destination chat ID. Required for: forward_message"
},
{
"properties": {
"action": { "const": "search_messages" },
"query": {
"type": "string",
"description": "Search query"
},
"chat_id": {
"type": "integer",
"description": "Chat ID to search within (omit for global search)"
},
"limit": {
"type": "integer",
"description": "Maximum number of results (default: 20)",
"default": 20
}
},
"required": ["action", "query"]
"message_ids": {
"type": "array",
"items": { "type": "integer" },
"description": "Message IDs. Required for: forward_message, delete_message"
},
{
"properties": {
"action": { "const": "get_updates" }
},
"required": ["action"]
"revoke": {
"type": "boolean",
"description": "Also delete for other participants (default: false). Used by: delete_message",
"default": false
},
"query": {
"type": "string",
"description": "Search query. Required for: search_messages"
}
]
}
}"#;
export!(TelegramTool);